Index: src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java
===================================================================
--- src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java	(revision 11427)
+++ src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java	(working copy)
@@ -88,6 +88,7 @@
     private int currentPhoto = -1;
 
     boolean useThumbs;
+    boolean useExternalViewer;
     private final ExecutorService thumbsLoaderExecutor =
             Executors.newSingleThreadExecutor(Utils.newThreadFactory("thumbnail-loader-%d", Thread.MIN_PRIORITY));
     private ThumbsLoader thumbsloader;
@@ -324,6 +325,8 @@
         entries.add(SeparatorLayerAction.INSTANCE);
         entries.add(new CorrelateGpxWithImages(this));
         entries.add(new ShowThumbnailAction(this));
+        entries.add(new UseExternalViewerAction(this));
+        entries.add(new SetExternalViewerAction(this));
         if (!menuAdditions.isEmpty()) {
             entries.add(SeparatorLayerAction.INSTANCE);
             entries.addAll(menuAdditions);
@@ -731,6 +734,26 @@
         }
     }
 
+    public void openCurrentPhotoInExternalViewer() {
+        if (data != null && !data.isEmpty() && currentPhoto >= 0 && currentPhoto < data.size()) {
+            String externalViewerPath = Main.pref.get("external.viewer.path", "");
+            if (externalViewerPath != "") {
+                String imagePath = data.get(currentPhoto).getFile().toString();
+                try {
+                    if (Main.isPlatformOsx()) {
+                        String[] command = {"open", "-a", externalViewerPath, imagePath};
+                        Runtime.getRuntime().exec(command);
+                    } else {
+                        String[] command = {externalViewerPath, imagePath};
+                        Runtime.getRuntime().exec(command);
+                    }
+                } catch (IOException ex) {
+                    System.err.println(tr("IOException: ")+ex.getMessage());
+                }
+            }
+        }
+    }
+
     /**
      * Removes a photo from the list of images by index.
      * @param idx Image index
@@ -882,6 +905,9 @@
                         currentPhoto = i;
                         ImageViewerDialog.showImage(GeoImageLayer.this, e);
                         Main.map.repaint();
+                        if (useExternalViewer) {
+                            openCurrentPhotoInExternalViewer();
+                        }
                         break;
                     }
                 }
@@ -1007,11 +1033,17 @@
     @Override
     public void jumpToNextMarker() {
         showNextPhoto();
+        if (useExternalViewer) {
+            openCurrentPhotoInExternalViewer();
+        }
     }
 
     @Override
     public void jumpToPreviousMarker() {
         showPreviousPhoto();
+        if (useExternalViewer) {
+            openCurrentPhotoInExternalViewer();
+        }
     }
 
     /**
@@ -1037,4 +1069,23 @@
             stopLoadThumbs();
         }
     }
+
+    /**
+     * Returns the current external viewer status.
+     * {@code true}: external viewer is used, {@code false}: external viewer is not used.
+     * @return Current external viewer status
+     * @since
+     */
+    public boolean isUseExternalViewer() {
+        return useExternalViewer;
+    }
+
+    /**
+     * Enables or disables the use of an external viewer.
+     * @param useExternalViewer New external viewer status
+     * @since
+     */
+    public void setUseExternalViewer(boolean useExternalViewer) {
+        this.useExternalViewer = useExternalViewer;
+    }
 }
Index: src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java	(revision 11427)
+++ src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java	(working copy)
@@ -47,6 +47,7 @@
     private static final String COMMAND_FIRST = "first";
     private static final String COMMAND_LAST = "last";
     private static final String COMMAND_COPY_PATH = "copypath";
+    private static final String COMMAND_OPEN_EXTERNAL = "openexternal";
 
     private final ImageDisplay imgDisplay = new ImageDisplay();
     private boolean centerView;
@@ -162,6 +163,10 @@
                 ImageProvider.get("dialogs", "zoom-best-fit"), tr("Zoom best fit and 1:1")));
         btnZoomBestFit.setPreferredSize(buttonDim);
 
+        JButton btnOpenExternal = new JButton(new ImageAction(COMMAND_OPEN_EXTERNAL,
+                ImageProvider.get("open"), tr("Open in external viewer")));
+        btnOpenExternal.setPreferredSize(buttonDim);
+
         btnCollapse = new JButton(new ImageAction(COMMAND_COLLAPSE,
                 ImageProvider.get("dialogs", "collapse"), tr("Move dialog to the side pane")));
         btnCollapse.setPreferredSize(new Dimension(20, 20));
@@ -178,6 +183,7 @@
         buttons.add(btnDeleteFromDisk);
         buttons.add(Box.createRigidArea(new Dimension(7, 0)));
         buttons.add(btnCopyPath);
+        buttons.add(btnOpenExternal);
 
         JPanel bottomPane = new JPanel(new GridBagLayout());
         GridBagConstraints gc = new GridBagConstraints();
@@ -248,6 +254,10 @@
                 if (currentLayer != null) {
                     currentLayer.copyCurrentPhotoPath();
                 }
+            } else if (COMMAND_OPEN_EXTERNAL.equals(action)) {
+                if (currentLayer != null) {
+                    currentLayer.openCurrentPhotoInExternalViewer();
+                }
             } else if (COMMAND_COLLAPSE.equals(action)) {
                 collapseButtonClicked = true;
                 detachedDialog.getToolkit().getSystemEventQueue().postEvent(new WindowEvent(detachedDialog, WindowEvent.WINDOW_CLOSING));
Index: src/org/openstreetmap/josm/gui/layer/geoimage/SetExternalViewerAction.java
===================================================================
--- src/org/openstreetmap/josm/gui/layer/geoimage/SetExternalViewerAction.java	(nonexistent)
+++ src/org/openstreetmap/josm/gui/layer/geoimage/SetExternalViewerAction.java	(working copy)
@@ -0,0 +1,80 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.layer.geoimage;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.JMenuItem;
+import javax.swing.JFileChooser;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.Layer.LayerAction;
+import org.openstreetmap.josm.gui.widgets.AbstractFileChooser;
+import org.openstreetmap.josm.gui.widgets.FileChooserManager;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+/**
+ * Choose the app to be used as the external image viewer.
+ * @since
+ */
+public class SetExternalViewerAction extends AbstractAction implements LayerAction {
+
+    private final transient GeoImageLayer layer;
+
+    /**
+     * Constructs a new {@code SetExternalViewerAction} action.
+     * @param layer image layer
+     */
+    public SetExternalViewerAction(GeoImageLayer layer) {
+        super(tr("Set external viewer"), ImageProvider.get("dialogs/next"));
+        putValue(SHORT_DESCRIPTION, tr("Choose the application to be used as the external image viewer."));
+        this.layer = layer;
+    }
+
+    /**
+     * This is called after the menu entry was selected.
+     * @param arg0 action event
+     */
+    @Override
+    public void actionPerformed(ActionEvent arg0) {
+        /** Work around a difference in behaviour between the native and non-native file choosers in OS X. */
+        if (Main.isPlatformOsx() && Main.pref.getBoolean("use.native.file.dialog", Main.isPlatformOsx())) {
+            AbstractFileChooser fc = new FileChooserManager(true, "external.viewer.lastdirectory", "").
+                    createFileChooser(false, tr("Choose the external image viewer"), null, JFileChooser.DIRECTORIES_ONLY).openFileChooser();
+            if (fc != null) {
+                File sel = fc.getSelectedFile();
+                if (sel != null) {
+                    Main.pref.put("external.viewer.path", sel.toString());
+                }
+            }
+        } else {
+            AbstractFileChooser fc = new FileChooserManager(true, "external.viewer.lastdirectory", "").
+                   createFileChooser(false, tr("Choose the external image viewer"), null, JFileChooser.FILES_ONLY).openFileChooser();
+            if (fc != null) {
+                File sel = fc.getSelectedFile();
+                if (sel != null) {
+                    Main.pref.put("external.viewer.path", sel.toString());
+                }
+            }
+        }
+    }
+
+    /** Create actual menu entry. */
+    @Override
+    public Component createMenuComponent() {
+        JMenuItem item = new JMenuItem(this);
+        return item;
+    }
+
+    /** Check if the current layer is supported. */
+    @Override
+    public boolean supportLayers(List<Layer> layers) {
+        return layers.size() == 1 && layers.get(0) instanceof GeoImageLayer;
+    }
+}
Index: src/org/openstreetmap/josm/gui/layer/geoimage/UseExternalViewerAction.java
===================================================================
--- src/org/openstreetmap/josm/gui/layer/geoimage/UseExternalViewerAction.java	(nonexistent)
+++ src/org/openstreetmap/josm/gui/layer/geoimage/UseExternalViewerAction.java	(working copy)
@@ -0,0 +1,59 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.layer.geoimage;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.JCheckBoxMenuItem;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.Layer.LayerAction;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+/**
+ * Toggle the the use of an external image viewer on and off.
+ * @since
+ */
+public class UseExternalViewerAction extends AbstractAction implements LayerAction {
+
+    private final transient GeoImageLayer layer;
+
+    /**
+     * Constructs a new {@code ToggleUseExtImageViewerAction} action.
+     * @param layer image layer
+     */
+    public UseExternalViewerAction(GeoImageLayer layer) {
+        super(tr("(Toggle) Use external viewer"), ImageProvider.get("dialogs/refresh"));
+        putValue(SHORT_DESCRIPTION, tr("Use external image viewer (as well as internal viewer)."));
+        this.layer = layer;
+    }
+
+    /**
+     * This is called after the menu entry was selected.
+     * @param arg0 action event
+     */
+    @Override
+    public void actionPerformed(ActionEvent arg0) {
+        layer.setUseExternalViewer(!layer.isUseExternalViewer());
+    }
+
+    /** Create actual menu entry and define if it is enabled or not. */
+    @Override
+    public Component createMenuComponent() {
+        JCheckBoxMenuItem toggleItem = new JCheckBoxMenuItem(this);
+        toggleItem.setEnabled(true);
+        toggleItem.setState(layer.isUseExternalViewer());
+        return toggleItem;
+    }
+
+    /** Check if the current layer is supported. */
+    @Override
+    public boolean supportLayers(List<Layer> layers) {
+        return layers.size() == 1 && layers.get(0) instanceof GeoImageLayer;
+    }
+}
