Index: /trunk/src/org/openstreetmap/josm/gui/MapView.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 2616)
+++ /trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 2617)
@@ -381,4 +381,5 @@
 
         Graphics2D tempG = offscreenBuffer.createGraphics();
+        tempG.setClip(g.getClip());
         tempG.setColor(Main.pref.getColor("background", Color.BLACK));
         tempG.fillRect(0, 0, getWidth(), getHeight());
Index: /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java	(revision 2616)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java	(revision 2617)
@@ -564,6 +564,6 @@
         gc.fill = GridBagConstraints.NONE;
         gc.weightx = gc.weighty = 0.0;
-        yLayer.loadThumbs = Main.pref.getBoolean("geoimage.showThumbs", false);
-        JCheckBox cbShowThumbs = new JCheckBox(tr("Show Thumbnail images on the map"), yLayer.loadThumbs);
+        yLayer.useThumbs = Main.pref.getBoolean("geoimage.showThumbs", false);
+        JCheckBox cbShowThumbs = new JCheckBox(tr("Show Thumbnail images on the map"), yLayer.useThumbs);
         panelTf.add(cbShowThumbs, gc);
 
@@ -635,14 +635,14 @@
             }
 
-            yLayer.loadThumbs = cbShowThumbs.isSelected();
+            yLayer.useThumbs = cbShowThumbs.isSelected();
 
             Main.pref.put("geoimage.doublegpstimezone", Double.toString(gpstimezone));
             Main.pref.put("geoimage.gpstimezone", Long.toString(- ((long) gpstimezone)));
             Main.pref.put("geoimage.delta", Long.toString(delta * 1000));
-            Main.pref.put("geoimage.showThumbs", yLayer.loadThumbs);
+            Main.pref.put("geoimage.showThumbs", yLayer.useThumbs);
             isOk = true;
 
-            if (yLayer.loadThumbs) {
-                yLayer.thumbsloader = new ThumbsLoader(yLayer.data);
+            if (yLayer.useThumbs) {
+                yLayer.thumbsloader = new ThumbsLoader(yLayer);
                 Thread t = new Thread(yLayer.thumbsloader);
                 t.setPriority(Thread.MIN_PRIORITY);
Index: /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java	(revision 2616)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java	(revision 2617)
@@ -9,5 +9,9 @@
 import static org.openstreetmap.josm.tools.I18n.trn;
 
+import java.awt.AlphaComposite;
+import java.awt.Color;
 import java.awt.Component;
+import java.awt.Composite;
+import java.awt.Dimension;
 import java.awt.Graphics2D;
 import java.awt.Image;
@@ -19,4 +23,6 @@
 import java.awt.event.MouseEvent;
 import java.awt.image.BufferedImage;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeEvent;
 import java.io.File;
 import java.io.IOException;
@@ -56,5 +62,5 @@
 import com.drew.metadata.exif.GpsDirectory;
 
-public class GeoImageLayer extends Layer {
+public class GeoImageLayer extends Layer implements PropertyChangeListener {
 
     List<ImageEntry> data;
@@ -71,6 +77,8 @@
     public long timeoffset = 0;
 
-    boolean loadThumbs;
+    boolean useThumbs = false;
     ThumbsLoader thumbsloader;
+    private BufferedImage offscreenBuffer;
+    boolean updateOffscreenBuffer = true;
 
     /*
@@ -295,4 +303,5 @@
         Collections.sort(data);
         this.data = data;
+        Main.map.mapView.addPropertyChangeListener(this);
     }
 
@@ -375,38 +384,98 @@
 
         setName(l.getName());
-
+    }
+
+    private Dimension scaledDimension(Image thumb) {
+        final double d = Main.map.mapView.getDist100Pixel();
+        final double size = 40 /*meter*/;     /* size of the photo on the map */
+        double s = size * 100 /*px*/ / d;
+
+        final double sMin = ThumbsLoader.minSize;
+        final double sMax = ThumbsLoader.maxSize;
+
+        if (s < sMin) {
+            s = sMin;
+        }
+        if (s > sMax) {
+            s = sMax;
+        }
+        final double f = s / sMax;  /* scale factor */
+
+        if (thumb == null)
+            return null;
+
+        return new Dimension(
+            (int) Math.round(f * thumb.getWidth(null)),
+            (int) Math.round(f * thumb.getHeight(null)));
     }
 
     @Override
     public void paint(Graphics2D g, MapView mv, Bounds bounds) {
-
-        for (ImageEntry e : data) {
+        int width = Main.map.mapView.getWidth();
+        int height = Main.map.mapView.getHeight();
+        Rectangle clip = g.getClipBounds();
+        if (useThumbs) {
+            if (null == offscreenBuffer || offscreenBuffer.getWidth() != width  // reuse the old buffer if possible
+                    || offscreenBuffer.getHeight() != height) {
+                offscreenBuffer = new BufferedImage(width, height,
+                        BufferedImage.TYPE_INT_ARGB);
+                updateOffscreenBuffer = true;
+            }
+
+            if (updateOffscreenBuffer) {
+                Graphics2D tempG = offscreenBuffer.createGraphics();
+                tempG.setColor(new Color(0,0,0,0));
+                Composite saveComp = tempG.getComposite();
+                tempG.setComposite(AlphaComposite.Clear);   // remove the old images
+                tempG.fillRect(0, 0, width, height);
+                tempG.setComposite(saveComp);
+
+                for (ImageEntry e : data) {
+                    if (e.pos == null)
+                        continue;
+                    Point p = mv.getPoint(e.pos);
+                    if (e.thumbnail != null) {
+                        Dimension d = scaledDimension(e.thumbnail);
+                        Rectangle target = new Rectangle(p.x - d.width / 2, p.y - d.height / 2, d.width, d.height);
+                        if (clip.intersects(target)) {
+                            tempG.drawImage(e.thumbnail, target.x, target.y, target.width, target.height, null);
+                        }
+                    }
+                    else { // thumbnail not loaded yet
+                        icon.paintIcon(mv, tempG,
+                                   p.x - icon.getIconWidth() / 2,
+                                   p.y - icon.getIconHeight() / 2);
+                    }
+                }
+                updateOffscreenBuffer = false;
+            }
+            g.drawImage(offscreenBuffer, 0, 0, null);
+        }
+        else {
+            for (ImageEntry e : data) {
+                if (e.pos == null)
+                    continue;
+                Point p = mv.getPoint(e.pos);
+                icon.paintIcon(mv, g,
+                           p.x - icon.getIconWidth() / 2,
+                           p.y - icon.getIconHeight() / 2);
+            }
+        }
+
+        if (currentPhoto >= 0 && currentPhoto < data.size()) {
+            ImageEntry e = data.get(currentPhoto);
+
             if (e.pos != null) {
                 Point p = mv.getPoint(e.pos);
-                if (e.thumbnail != null && e.thumbnail.getWidth(null) > 0 && e.thumbnail.getHeight(null) > 0) {
-                    g.drawImage(e.thumbnail,
-                                p.x - e.thumbnail.getWidth(null) / 2,
-                                p.y - e.thumbnail.getHeight(null) / 2, null);
-                }
-                else {
-                icon.paintIcon(mv, g,
-                               p.x - icon.getIconWidth() / 2,
-                               p.y - icon.getIconHeight() / 2);
-                }
-            }
-        }
-
-        // Draw the selection on top of the other pictures.
-        if (currentPhoto >= 0 && currentPhoto < data.size()) {
-            ImageEntry e = data.get(currentPhoto);
-
-            if (e.pos != null) {
-                Point p = mv.getPoint(e.pos);
-
-                Rectangle r = new Rectangle(p.x - selectedIcon.getIconWidth() / 2,
-                                            p.y - selectedIcon.getIconHeight() / 2,
-                                            selectedIcon.getIconWidth(),
-                                            selectedIcon.getIconHeight());
-                selectedIcon.paintIcon(mv, g, r.x, r.y);
+
+                if (e.thumbnail != null) {
+                    Dimension d = scaledDimension(e.thumbnail);
+                    g.setColor(new Color(128, 0, 0, 122));
+                    g.fillRect(p.x - d.width / 2, p.y - d.height / 2, d.width, d.height);
+                } else {
+                    selectedIcon.paintIcon(mv, g,
+                                p.x - selectedIcon.getIconWidth() / 2,
+                                p.y - selectedIcon.getIconHeight() / 2);
+                }
             }
         }
@@ -500,5 +569,5 @@
 
     public void checkPreviousNextButtons() {
-        System.err.println("check: " + currentPhoto);
+//        System.err.println("showing image " + currentPhoto);
         ImageViewerDialog.setNextEnabled(currentPhoto < data.size() - 1);
         ImageViewerDialog.setPreviousEnabled(currentPhoto > 0);
@@ -517,4 +586,5 @@
             }
         }
+        updateOffscreenBuffer = true;
         Main.main.map.repaint();
     }
@@ -534,5 +604,4 @@
 
             @Override public void mouseReleased(MouseEvent ev) {
-
                 if (ev.getButton() != MouseEvent.BUTTON1) {
                     return;
@@ -541,6 +610,4 @@
                     return;
                 }
-
-                ImageViewerDialog d = ImageViewerDialog.getInstance();
 
                 for (int i = data.size() - 1; i >= 0; --i) {
@@ -549,8 +616,14 @@
                         continue;
                     Point p = Main.map.mapView.getPoint(e.pos);
-                    Rectangle r = new Rectangle(p.x - icon.getIconWidth() / 2,
-                                                p.y - icon.getIconHeight() / 2,
-                                                icon.getIconWidth(),
-                                                icon.getIconHeight());
+                    Rectangle r;
+                    if (e.thumbnail != null) {
+                        Dimension d = scaledDimension(e.thumbnail);
+                        r = new Rectangle(p.x - d.width / 2, p.y - d.height / 2, d.width, d.height);
+                    } else {
+                        r = new Rectangle(p.x - icon.getIconWidth() / 2,
+                                            p.y - icon.getIconHeight() / 2,
+                                            icon.getIconWidth(),
+                                            icon.getIconHeight());
+                    }
                     if (r.contains(ev.getPoint())) {
                         currentPhoto = i;
@@ -560,5 +633,4 @@
                     }
                 }
-                Main.map.mapView.repaint();
             }
         };
@@ -577,4 +649,7 @@
             public void layerRemoved(Layer oldLayer) {
                 if (oldLayer == GeoImageLayer.this) {
+                    if (thumbsloader != null) {
+                        thumbsloader.stop = true;
+                    }
                     Main.map.mapView.removeMouseListener(mouseAdapter);
                     currentPhoto = -1;
@@ -585,9 +660,8 @@
         });
     }
-    
-    @Override
-    public void destroy() {
-        if (thumbsloader != null) {
-            thumbsloader.stop = true;
+
+    public void propertyChange(PropertyChangeEvent evt) {
+        if ("center".equals(evt.getPropertyName()) || "scale".equals(evt.getPropertyName())) {
+            updateOffscreenBuffer = true;
         }
     }
Index: /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java	(revision 2616)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java	(revision 2617)
@@ -201,8 +201,8 @@
     public void displayImage(GeoImageLayer layer, ImageEntry entry) {
         synchronized(this) {
-            if (currentLayer == layer && currentEntry == entry) {
-                repaint();
-                return;
-            }
+//            if (currentLayer == layer && currentEntry == entry) {
+//                repaint();
+//                return;
+//            }                     TODO: pop up image dialog but don't load image again
 
             if (centerView && Main.map != null && entry != null && entry.pos != null) {
Index: /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ThumbsLoader.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ThumbsLoader.java	(revision 2616)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ThumbsLoader.java	(revision 2617)
@@ -5,7 +5,8 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.awt.MediaTracker;
 import java.awt.Graphics2D;
 import java.awt.Image;
+import java.awt.MediaTracker;
+import java.awt.Rectangle;
 import java.awt.Toolkit;
 import java.awt.image.BufferedImage;
@@ -19,12 +20,16 @@
 
 public class ThumbsLoader implements Runnable {
+        public static final int maxSize = 120;
+        public static final int minSize = 22;
         volatile boolean stop = false;
         List<ImageEntry> data;
+        GeoImageLayer layer;
         MediaTracker tracker;
         CacheFiles cache;
         boolean cacheOff = Main.pref.getBoolean("geoimage.noThumbnailCache", false);
-        
-        public ThumbsLoader(List<ImageEntry> data) {
-            this.data = new ArrayList<ImageEntry>(data);
+
+        public ThumbsLoader(GeoImageLayer layer) {
+            this.layer = layer;
+            this.data = new ArrayList<ImageEntry>(layer.data);
             if (!cacheOff) {
                 cache = new CacheFiles("geoimage-thumbnails", false);
@@ -39,11 +44,21 @@
             for (int i = 0; i < data.size(); i++) {
                 if (stop) return;
+
                 System.err.print("fetching image "+i);
+
                 data.get(i).thumbnail = loadThumb(data.get(i));
+
                 if (Main.map != null && Main.map.mapView != null) {
+                    try {
+                        layer.updateOffscreenBuffer = true;
+                    } catch (Exception e) {}
                     Main.map.mapView.repaint();
                 }
             }
-            (new Thread() {
+            try {
+                layer.updateOffscreenBuffer = true;
+            } catch (Exception e) {}
+            Main.map.mapView.repaint();
+            (new Thread() {             // clean up the garbage - shouldn't hurt
                 public void run() {
                     try {
@@ -56,17 +71,16 @@
 
         }
-        
+
         private BufferedImage loadThumb(ImageEntry entry) {
-            final int size = 16;
-            final String cacheIdent = entry.file.toString()+":"+size;
-            
+            final String cacheIdent = entry.file.toString()+":"+maxSize;
+
             if (!cacheOff) {
                 BufferedImage cached = cache.getImg(cacheIdent);
                 if(cached != null) {
-                    System.err.println(" from cache"); 
+                    System.err.println(" from cache");
                     return cached;
                 }
             }
-            
+
             Image img = Toolkit.getDefaultToolkit().createImage(entry.file.getPath());
             tracker.addImage(img, 0);
@@ -77,19 +91,31 @@
                 return null;
             }
-            BufferedImage scaledBI = new BufferedImage(16, 16, BufferedImage.TYPE_INT_RGB);
+            if (tracker.isErrorID(1) || img.getWidth(null) <= 0 || img.getHeight(null) <= 0) {
+                System.err.println(" Invalid image");
+                return null;
+            }
+            Rectangle targetSize = ImageDisplay.calculateDrawImageRectangle(
+                new Rectangle(0, 0, img.getWidth(null), img.getHeight(null)),
+                new Rectangle(0, 0, maxSize, maxSize));
+            BufferedImage scaledBI = new BufferedImage(targetSize.width, targetSize.height, BufferedImage.TYPE_INT_RGB);
             Graphics2D g = scaledBI.createGraphics();
-            while (!g.drawImage(img, 0, 0, 16, 16, null))
+            while (!g.drawImage(img, 0, 0, targetSize.width, targetSize.height, null))
             {
                 try {
                     Thread.sleep(10);
-                } catch(InterruptedException ie) {} //FIXME: timeout?
+                } catch(InterruptedException ie) {}
             }
             g.dispose();
             tracker.removeImage(img);
-            
-            if (!cacheOff && scaledBI != null && scaledBI.getWidth() > 0) {
+
+            if (scaledBI == null || scaledBI.getWidth() <= 0 || scaledBI.getHeight() <= 0) {
+                System.err.println(" Invalid image");
+                return null;
+            }
+
+            if (!cacheOff) {
                 cache.saveImg(cacheIdent, scaledBI);
             }
-            
+
             System.err.println("");
             return scaledBI;
