Index: /trunk/src/org/openstreetmap/josm/data/IQuadBucketType.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/IQuadBucketType.java	(revision 17459)
+++ /trunk/src/org/openstreetmap/josm/data/IQuadBucketType.java	(revision 17459)
@@ -0,0 +1,19 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data;
+
+import org.openstreetmap.josm.data.osm.BBox;
+import org.openstreetmap.josm.data.osm.QuadBuckets;
+
+/**
+ * The minimum necessary interface to use {@link QuadBuckets}.
+ * @author Taylor Smock
+ * @since 17459
+ */
+@FunctionalInterface
+public interface IQuadBucketType {
+    /**
+     * Fetches the bounding box of the primitive.
+     * @return Bounding box of the object
+     */
+    BBox getBBox();
+}
Index: /trunk/src/org/openstreetmap/josm/data/ImageData.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/ImageData.java	(revision 17458)
+++ /trunk/src/org/openstreetmap/josm/data/ImageData.java	(revision 17459)
@@ -12,4 +12,5 @@
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.gpx.GpxImageEntry;
+import org.openstreetmap.josm.data.osm.QuadBuckets;
 import org.openstreetmap.josm.gui.layer.geoimage.ImageEntry;
 import org.openstreetmap.josm.tools.ListenerList;
@@ -42,4 +43,5 @@
 
     private final ListenerList<ImageDataUpdateListener> listeners = ListenerList.create();
+    private final QuadBuckets<ImageEntry> geoImages = new QuadBuckets<>();
 
     /**
@@ -61,4 +63,5 @@
             this.data = new ArrayList<>();
         }
+        this.geoImages.addAll(data);
         selectedImagesIndex.add(-1);
     }
@@ -86,4 +89,5 @@
     public void mergeFrom(ImageData otherData) {
         data.addAll(otherData.getImages());
+        this.geoImages.addAll(otherData.getImages());
         Collections.sort(data);
 
@@ -154,4 +158,14 @@
 
     /**
+     * Search for images in a bounds
+     * @param bounds The bounds to search
+     * @return images in the bounds
+     * @since 17459
+     */
+    public Collection<ImageEntry> searchImages(Bounds bounds) {
+        return this.geoImages.search(bounds.toBBox());
+    }
+
+    /**
      * Select the next image of the sequence
      */
@@ -266,4 +280,5 @@
         for (ImageEntry img: getSelectedImages()) {
             data.remove(img);
+            this.geoImages.remove(img);
         }
         if (selectedImagesIndex.get(0) >= data.size()) {
@@ -291,4 +306,5 @@
     public void removeImage(ImageEntry img) {
         data.remove(img);
+        this.geoImages.remove(img);
         notifyImageUpdate();
     }
@@ -301,4 +317,6 @@
     public void updateImagePosition(ImageEntry img, LatLon newPos) {
         img.setPos(newPos);
+        this.geoImages.remove(img);
+        this.geoImages.add(img);
         afterImageUpdated(img);
     }
Index: /trunk/src/org/openstreetmap/josm/data/gpx/GpxImageEntry.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/gpx/GpxImageEntry.java	(revision 17458)
+++ /trunk/src/org/openstreetmap/josm/data/gpx/GpxImageEntry.java	(revision 17459)
@@ -9,6 +9,8 @@
 import java.util.function.Consumer;
 
+import org.openstreetmap.josm.data.IQuadBucketType;
 import org.openstreetmap.josm.data.coor.CachedLatLon;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.BBox;
 import org.openstreetmap.josm.tools.ExifReader;
 import org.openstreetmap.josm.tools.JosmRuntimeException;
@@ -29,5 +31,5 @@
  * @since 14205 (extracted from gui.layer.geoimage.ImageEntry)
  */
-public class GpxImageEntry implements Comparable<GpxImageEntry> {
+public class GpxImageEntry implements Comparable<GpxImageEntry>, IQuadBucketType {
     private File file;
     private Integer exifOrientation;
@@ -540,4 +542,10 @@
    }
 
+    @Override
+    public BBox getBBox() {
+        // new BBox(LatLon) is null safe.
+        return new BBox(this.getExifCoor());
+    }
+
     /**
      * Remove the flag that indicates new GPS data.
Index: /trunk/src/org/openstreetmap/josm/data/osm/IPrimitive.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/IPrimitive.java	(revision 17458)
+++ /trunk/src/org/openstreetmap/josm/data/osm/IPrimitive.java	(revision 17459)
@@ -6,4 +6,5 @@
 import java.util.Map;
 
+import org.openstreetmap.josm.data.IQuadBucketType;
 import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
 import org.openstreetmap.josm.tools.LanguageInfo;
@@ -13,5 +14,5 @@
  * @since 4098
  */
-public interface IPrimitive extends Tagged, PrimitiveId, Stylable, Comparable<IPrimitive> {
+public interface IPrimitive extends IQuadBucketType, Tagged, PrimitiveId, Stylable, Comparable<IPrimitive> {
 
     /**
@@ -446,4 +447,5 @@
      * @since 13764
      */
+    @Override
     BBox getBBox();
 
Index: /trunk/src/org/openstreetmap/josm/data/osm/QuadBuckets.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/QuadBuckets.java	(revision 17458)
+++ /trunk/src/org/openstreetmap/josm/data/osm/QuadBuckets.java	(revision 17459)
@@ -11,4 +11,5 @@
 import java.util.stream.IntStream;
 
+import org.openstreetmap.josm.data.IQuadBucketType;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.coor.QuadTiling;
@@ -20,8 +21,8 @@
  *
  * This class is (no longer) thread safe.
- * @param <T> type of primitives
- * @since 2165
+ * @param <T> type of object extending {@link IQuadBucketType}.
+ * @since 2165 ({@link IPrimitive} only), xxx for {@link IQuadBucketType}
  */
-public class QuadBuckets<T extends IPrimitive> implements Collection<T> {
+public class QuadBuckets<T extends IQuadBucketType> implements Collection<T> {
     private static final boolean CONSISTENCY_TESTING = false;
     private static final byte NW_INDEX = 1;
@@ -36,5 +37,5 @@
     private static final int MAX_OBJECTS_PER_NODE = 48;
 
-    static class QBLevel<T extends IPrimitive> extends BBox {
+    static class QBLevel<T extends IQuadBucketType> extends BBox {
         private final byte level;
         private final byte index;
Index: /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java	(revision 17458)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java	(revision 17459)
@@ -38,7 +38,7 @@
 import org.openstreetmap.josm.actions.AutoScaleAction;
 import org.openstreetmap.josm.actions.RenameLayerAction;
-import org.openstreetmap.josm.actions.mapmode.SelectLassoAction;
 import org.openstreetmap.josm.actions.mapmode.MapMode;
 import org.openstreetmap.josm.actions.mapmode.SelectAction;
+import org.openstreetmap.josm.actions.mapmode.SelectLassoAction;
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.Data;
@@ -562,5 +562,5 @@
                 tempG.setComposite(saveComp);
 
-                for (ImageEntry e : data.getImages()) {
+                for (ImageEntry e : data.searchImages(bounds)) {
                     paintImage(e, mv, clip, tempG);
                 }
@@ -573,5 +573,5 @@
             g.drawImage(offscreenBuffer, 0, 0, null);
         } else {
-            for (ImageEntry e : data.getImages()) {
+            for (ImageEntry e : data.searchImages(bounds)) {
                 if (e.getPos() == null) {
                     continue;
