Index: trunk/src/org/openstreetmap/josm/data/gpx/GpxImageEntry.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/GpxImageEntry.java	(revision 17878)
+++ trunk/src/org/openstreetmap/josm/data/gpx/GpxImageEntry.java	(revision 17880)
@@ -207,4 +207,12 @@
     public File getFile() {
         return file;
+    }
+
+    /**
+     * Returns a display name for this entry
+     * @return a display name for this entry
+     */
+    public String getDisplayName() {
+        return file == null ? "" : file.getName();
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/MainMenu.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MainMenu.java	(revision 17878)
+++ trunk/src/org/openstreetmap/josm/gui/MainMenu.java	(revision 17880)
@@ -130,4 +130,5 @@
 import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeEvent;
 import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener;
+import org.openstreetmap.josm.gui.layer.geoimage.WikimediaCommonsLoader;
 import org.openstreetmap.josm.gui.mappaint.MapPaintMenu;
 import org.openstreetmap.josm.gui.preferences.imagery.ImageryPreference;
@@ -748,4 +749,5 @@
         add(fileMenu, searchNotes);
         add(fileMenu, downloadNotesInView);
+        add(fileMenu, new WikimediaCommonsLoader.Action());
         add(fileMenu, downloadReferrers);
         add(fileMenu, update);
Index: trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java	(revision 17878)
+++ trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java	(revision 17880)
@@ -702,5 +702,5 @@
                 @Override
                 public String getElementAt(int i) {
-                    return yLayer.getImageData().getImages().get(i).getFile().getName();
+                    return yLayer.getImageData().getImages().get(i).getDisplayName();
                 }
 
Index: trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageDisplay.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageDisplay.java	(revision 17878)
+++ trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageDisplay.java	(revision 17880)
@@ -703,5 +703,5 @@
             }
             if (errorLoading) {
-                String loadingStr = tr("Error on file {0}", entry.getFile().getName());
+                String loadingStr = tr("Error on file {0}", entry.getDisplayName());
                 Rectangle2D noImageSize = g.getFontMetrics(g.getFont()).getStringBounds(loadingStr, g);
                 g.drawString(loadingStr,
@@ -749,7 +749,7 @@
             // we are probably still loading the image. (oldEntry gets set to entry when the image finishes loading).
             if (!errorLoading) {
-                errorMessage = tr("Loading {0}", entry.getFile().getName());
+                errorMessage = tr("Loading {0}", entry.getDisplayName());
             } else {
-                errorMessage = tr("Error on file {0}", entry.getFile().getName());
+                errorMessage = tr("Error on file {0}", entry.getDisplayName());
             }
         } else {
Index: trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageEntry.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageEntry.java	(revision 17878)
+++ trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageEntry.java	(revision 17880)
@@ -10,4 +10,6 @@
 import java.io.IOException;
 import java.io.UncheckedIOException;
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.util.Collections;
 import java.util.Objects;
@@ -29,5 +31,5 @@
  * @since 2662
  */
-public final class ImageEntry extends GpxImageEntry {
+public class ImageEntry extends GpxImageEntry {
 
     private Image thumbnail;
@@ -141,11 +143,16 @@
      */
     public BufferedImage read(Dimension target) throws IOException {
-        Logging.info(tr("Loading {0}", getFile().getPath()));
-        BufferedImage image = ImageProvider.read(getFile(), false, false,
+        URL imageUrl = getImageUrl();
+        Logging.info(tr("Loading {0}", imageUrl));
+        BufferedImage image = ImageProvider.read(imageUrl, false, false,
                 r -> target == null ? r.getDefaultReadParam() : withSubsampling(r, target));
         Logging.debug("Loaded {0} with dimensions {1}x{2} memoryTaken={3}m exifOrientationSwitchedDimension={4}",
-                getFile().getPath(), image.getWidth(), image.getHeight(), image.getWidth() * image.getHeight() * 4 / 1024 / 1024,
+                imageUrl, image.getWidth(), image.getHeight(), image.getWidth() * image.getHeight() * 4 / 1024 / 1024,
                 ExifReader.orientationSwitchesDimensions(getExifOrientation()));
         return applyExifRotation(image);
+    }
+
+    protected URL getImageUrl() throws MalformedURLException {
+        return getFile().toURI().toURL();
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java	(revision 17878)
+++ trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java	(revision 17880)
@@ -372,5 +372,5 @@
         public void actionPerformed(ActionEvent e) {
             if (currentData != null) {
-                ClipboardUtils.copyString(currentData.getSelectedImage().getFile().toString());
+                ClipboardUtils.copyString(String.valueOf(currentData.getSelectedImage().getFile()));
             }
         }
@@ -461,5 +461,5 @@
             setPreviousEnabled(data.hasPreviousImage());
             btnDelete.setEnabled(true);
-            btnDeleteFromDisk.setEnabled(true);
+            btnDeleteFromDisk.setEnabled(entry.getFile() != null);
             btnCopyPath.setEnabled(true);
 
@@ -469,6 +469,6 @@
                 imgDisplay.setImage(entry);
             }
-            setTitle(tr("Geotagged Images") + (entry.getFile() != null ? " - " + entry.getFile().getName() : ""));
-            StringBuilder osd = new StringBuilder(entry.getFile() != null ? entry.getFile().getName() : "");
+            setTitle(tr("Geotagged Images") + (!entry.getDisplayName().isEmpty() ? " - " + entry.getDisplayName() : ""));
+            StringBuilder osd = new StringBuilder(entry.getDisplayName());
             if (entry.getElevation() != null) {
                 osd.append(tr("\nAltitude: {0} m", Math.round(entry.getElevation())));
Index: trunk/src/org/openstreetmap/josm/gui/layer/geoimage/WikimediaCommonsEntry.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/geoimage/WikimediaCommonsEntry.java	(revision 17880)
+++ trunk/src/org/openstreetmap/josm/gui/layer/geoimage/WikimediaCommonsEntry.java	(revision 17880)
@@ -0,0 +1,35 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.layer.geoimage;
+
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.tools.Mediawiki;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * A geocoded image from <a href="https://commons.wikimedia.org/">Wikimedia Commons</a>
+ */
+class WikimediaCommonsEntry extends ImageEntry {
+    private final String title;
+
+    WikimediaCommonsEntry(String title, LatLon latLon) {
+        this.title = title.replaceFirst("^File:", "").replace(" ", "_");
+        setPos(latLon);
+    }
+
+    @Override
+    protected URL getImageUrl() throws MalformedURLException {
+        return new URL(Mediawiki.getImageUrl("https://upload.wikimedia.org/wikipedia/commons", title));
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "File:" + title;
+    }
+
+    @Override
+    public String toString() {
+        return "File:" + title;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/layer/geoimage/WikimediaCommonsLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/geoimage/WikimediaCommonsLayer.java	(revision 17880)
+++ trunk/src/org/openstreetmap/josm/gui/layer/geoimage/WikimediaCommonsLayer.java	(revision 17880)
@@ -0,0 +1,24 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.layer.geoimage;
+
+import org.openstreetmap.josm.tools.ImageProvider;
+
+import javax.swing.Icon;
+import java.util.List;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+/**
+ * A layer showing geocoded images from <a href="https://commons.wikimedia.org/">Wikimedia Commons</a>
+ */
+class WikimediaCommonsLayer extends GeoImageLayer {
+    WikimediaCommonsLayer(List<ImageEntry> imageEntries) {
+        super(imageEntries, null);
+        setName(tr("Wikimedia Commons"));
+    }
+
+    @Override
+    public Icon getIcon() {
+        return ImageProvider.get("wikimedia_commons", ImageProvider.ImageSizes.LAYER);
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/layer/geoimage/WikimediaCommonsLoader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/geoimage/WikimediaCommonsLoader.java	(revision 17880)
+++ trunk/src/org/openstreetmap/josm/gui/layer/geoimage/WikimediaCommonsLoader.java	(revision 17880)
@@ -0,0 +1,78 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.layer.geoimage;
+
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.PleaseWaitRunnable;
+import org.openstreetmap.josm.io.OsmTransferException;
+import org.openstreetmap.josm.tools.Logging;
+import org.openstreetmap.josm.tools.Mediawiki;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPathExpressionException;
+import java.awt.event.ActionEvent;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+/**
+ * Loads geocoded images from <a href="https://commons.wikimedia.org/">Wikimedia Commons</a> for the given bounding box.
+ */
+public class WikimediaCommonsLoader extends PleaseWaitRunnable {
+    protected String apiUrl = "https://commons.wikimedia.org/w/api.php";
+    protected GeoImageLayer layer;
+    private final Bounds bounds;
+
+    /**
+     * Constructs a new {@code WikimediaCommonsLoader}
+     * @param bounds The bounds to load
+     */
+    public WikimediaCommonsLoader(Bounds bounds) {
+        super(tr("Load images from Wikimedia Commons"));
+        this.bounds = bounds;
+    }
+
+    @Override
+    protected void realRun() throws SAXException, IOException, OsmTransferException {
+        List<ImageEntry> imageEntries = new ArrayList<>();
+        try {
+            new Mediawiki(apiUrl).searchGeoImages(bounds, (title, latLon) -> imageEntries.add(new WikimediaCommonsEntry(title, latLon)));
+        } catch (ParserConfigurationException | XPathExpressionException e) {
+            throw new IllegalStateException(e);
+        }
+        Logging.info("Loaded {0} images from Wikimedia Commons", imageEntries.size());
+        layer = new WikimediaCommonsLayer(imageEntries);
+    }
+
+    @Override
+    protected void finish() {
+        MainApplication.getLayerManager().addLayer(layer);
+    }
+
+    @Override
+    protected void cancel() {
+        // do nothing
+    }
+
+    public static class Action extends JosmAction {
+        public Action() {
+            super(tr("Load images from Wikimedia Commons"), "wikimedia_commons", null, null, false);
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            Bounds bounds = MainApplication.getMap().mapView.getRealBounds();
+            MainApplication.worker.execute(new WikimediaCommonsLoader(bounds));
+        }
+
+        @Override
+        protected void updateEnabledState() {
+            setEnabled(MainApplication.isDisplayingMapView());
+        }
+    }
+
+}
Index: trunk/src/org/openstreetmap/josm/tools/ImageProvider.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/ImageProvider.java	(revision 17878)
+++ trunk/src/org/openstreetmap/josm/tools/ImageProvider.java	(revision 17880)
@@ -1549,47 +1549,4 @@
      */
     public static BufferedImage read(File input, boolean readMetadata, boolean enforceTransparency) throws IOException {
-        return read(input, readMetadata, enforceTransparency, ImageReader::getDefaultReadParam);
-    }
-
-    /**
-     * Returns a <code>BufferedImage</code> as the result of decoding
-     * a supplied <code>File</code> with an <code>ImageReader</code>
-     * chosen automatically from among those currently registered.
-     * The <code>File</code> is wrapped in an
-     * <code>ImageInputStream</code>.  If no registered
-     * <code>ImageReader</code> claims to be able to read the
-     * resulting stream, <code>null</code> is returned.
-     *
-     * <p> The current cache settings from <code>getUseCache</code>and
-     * <code>getCacheDirectory</code> will be used to control caching in the
-     * <code>ImageInputStream</code> that is created.
-     *
-     * <p> Note that there is no <code>read</code> method that takes a
-     * filename as a <code>String</code>; use this method instead after
-     * creating a <code>File</code> from the filename.
-     *
-     * <p> This method does not attempt to locate
-     * <code>ImageReader</code>s that can read directly from a
-     * <code>File</code>; that may be accomplished using
-     * <code>IIORegistry</code> and <code>ImageReaderSpi</code>.
-     *
-     * @param input a <code>File</code> to read from.
-     * @param readMetadata if {@code true}, makes sure to read image metadata to detect transparency color, if any.
-     * In that case the color can be retrieved later through {@link #PROP_TRANSPARENCY_COLOR}.
-     * Always considered {@code true} if {@code enforceTransparency} is also {@code true}
-     * @param enforceTransparency if {@code true}, makes sure to read image metadata and, if the image does not
-     * provide an alpha channel but defines a {@code TransparentColor} metadata node, that the resulting image
-     * has a transparency set to {@code TRANSLUCENT} and uses the correct transparent color.
-     * @param readParamFunction a function to compute the read parameters from the image reader
-     *
-     * @return a <code>BufferedImage</code> containing the decoded contents of the input, or <code>null</code>.
-     *
-     * @throws IllegalArgumentException if <code>input</code> is <code>null</code>.
-     * @throws IOException if an error occurs during reading.
-     * @see BufferedImage#getProperty
-     * @since xxx
-     */
-    public static BufferedImage read(File input, boolean readMetadata, boolean enforceTransparency,
-                                     Function<ImageReader, ImageReadParam> readParamFunction) throws IOException {
         CheckParameterUtil.ensureParameterNotNull(input, "input");
         if (!input.canRead()) {
@@ -1601,5 +1558,5 @@
             throw new IIOException("Can't create an ImageInputStream!");
         }
-        BufferedImage bi = read(stream, readMetadata, enforceTransparency, readParamFunction);
+        BufferedImage bi = read(stream, readMetadata, enforceTransparency);
         if (bi == null) {
             stream.close();
@@ -1688,9 +1645,47 @@
      */
     public static BufferedImage read(URL input, boolean readMetadata, boolean enforceTransparency) throws IOException {
+        return read(input, readMetadata, enforceTransparency, ImageReader::getDefaultReadParam);
+    }
+
+    /**
+     * Returns a <code>BufferedImage</code> as the result of decoding
+     * a supplied <code>URL</code> with an <code>ImageReader</code>
+     * chosen automatically from among those currently registered.  An
+     * <code>InputStream</code> is obtained from the <code>URL</code>,
+     * which is wrapped in an <code>ImageInputStream</code>.  If no
+     * registered <code>ImageReader</code> claims to be able to read
+     * the resulting stream, <code>null</code> is returned.
+     *
+     * <p> The current cache settings from <code>getUseCache</code>and
+     * <code>getCacheDirectory</code> will be used to control caching in the
+     * <code>ImageInputStream</code> that is created.
+     *
+     * <p> This method does not attempt to locate
+     * <code>ImageReader</code>s that can read directly from a
+     * <code>URL</code>; that may be accomplished using
+     * <code>IIORegistry</code> and <code>ImageReaderSpi</code>.
+     *
+     * @param input a <code>URL</code> to read from.
+     * @param readMetadata if {@code true}, makes sure to read image metadata to detect transparency color for non translucent images, if any.
+     * In that case the color can be retrieved later through {@link #PROP_TRANSPARENCY_COLOR}.
+     * Always considered {@code true} if {@code enforceTransparency} is also {@code true}
+     * @param enforceTransparency if {@code true}, makes sure to read image metadata and, if the image does not
+     * provide an alpha channel but defines a {@code TransparentColor} metadata node, that the resulting image
+     * has a transparency set to {@code TRANSLUCENT} and uses the correct transparent color.
+     * @param readParamFunction a function to compute the read parameters from the image reader
+     *
+     * @return a <code>BufferedImage</code> containing the decoded contents of the input, or <code>null</code>.
+     *
+     * @throws IllegalArgumentException if <code>input</code> is <code>null</code>.
+     * @throws IOException if an error occurs during reading.
+     * @since 17880
+     */
+    public static BufferedImage read(URL input, boolean readMetadata, boolean enforceTransparency,
+                                     Function<ImageReader, ImageReadParam> readParamFunction) throws IOException {
         CheckParameterUtil.ensureParameterNotNull(input, "input");
 
         try (InputStream istream = Utils.openStream(input)) {
             ImageInputStream stream = createImageInputStream(istream); // NOPMD
-            BufferedImage bi = read(stream, readMetadata, enforceTransparency);
+            BufferedImage bi = read(stream, readMetadata, enforceTransparency, readParamFunction);
             if (bi == null) {
                 stream.close();
Index: trunk/src/org/openstreetmap/josm/tools/Mediawiki.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/Mediawiki.java	(revision 17878)
+++ trunk/src/org/openstreetmap/josm/tools/Mediawiki.java	(revision 17880)
@@ -7,4 +7,5 @@
 import java.util.List;
 import java.util.Optional;
+import java.util.function.BiConsumer;
 import java.util.stream.Collectors;
 
@@ -15,6 +16,10 @@
 import javax.xml.xpath.XPathFactory;
 
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.coor.LatLon;
 import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 import org.xml.sax.SAXException;
 
@@ -53,10 +58,5 @@
                 .collect(Collectors.joining(Utils.encodeUrl("|")))
         );
-        final HttpClient.Response conn = HttpClient.create(url).connect();
-        final Document document;
-        try (InputStream content = conn.getContent()) {
-            document = XmlUtils.parseSafeDOM(content);
-        }
-        conn.disconnect();
+        final Document document = getDocument(url);
         final XPath xPath = XPathFactory.newInstance().newXPath();
         for (String page : distinctPages) {
@@ -75,4 +75,44 @@
     }
 
+    private Document getDocument(URL url) throws IOException, ParserConfigurationException, SAXException {
+        final HttpClient.Response conn = HttpClient.create(url).connect();
+        try (InputStream content = conn.getContent()) {
+            return XmlUtils.parseSafeDOM(content);
+        } finally {
+            conn.disconnect();
+        }
+    }
+
+    /**
+     * Searches geocoded images from <a href="https://commons.wikimedia.org/">Wikimedia Commons</a> for the given bounding box.
+     * @param bounds the bounds to load
+     * @param imageConsumer a consumer to receive the file title and the coordinates for every geocoded image
+     * @throws IOException if any I/O error occurs
+     * @throws ParserConfigurationException if a parser cannot be created
+     * @throws SAXException if any XML error occurs
+     * @throws XPathExpressionException if any error in an XPath expression occurs
+     */
+    public void searchGeoImages(Bounds bounds, BiConsumer<String, LatLon> imageConsumer)
+            throws IOException, ParserConfigurationException, SAXException, XPathExpressionException {
+        final URL url = new URL(baseUrl +
+                "?format=xml" +
+                "&action=query" +
+                "&list=geosearch" +
+                "&gsnamespace=6" +
+                "&gslimit=500" +
+                "&gsprop=type|name" +
+                "&gsbbox=" + bounds.getMaxLat() + "|" + bounds.getMinLon() + "|" + bounds.getMinLat() + "|" + bounds.getMaxLon());
+        final Document document = getDocument(url);
+        final XPath xPath = XPathFactory.newInstance().newXPath();
+        NodeList nodes = (NodeList) xPath.evaluate("/api/query/geosearch/gs", document, XPathConstants.NODESET);
+        for (int i = 0; i < nodes.getLength(); i++) {
+            NamedNodeMap attributes = nodes.item(i).getAttributes();
+            String title = attributes.getNamedItem("title").getNodeValue();
+            double lat = Double.parseDouble(attributes.getNamedItem("lat").getNodeValue());
+            double lon = Double.parseDouble(attributes.getNamedItem("lon").getNodeValue());
+            imageConsumer.accept(title, new LatLon(lat, lon));
+        }
+    }
+
     /**
      * Computes the URL for the given filename on the MediaWiki server
