Index: trunk/src/org/openstreetmap/josm/tools/ImageProvider.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/ImageProvider.java	(revision 4711)
+++ trunk/src/org/openstreetmap/josm/tools/ImageProvider.java	(revision 4712)
@@ -77,5 +77,6 @@
 
     /**
-     * Return an image from the specified location.
+     * Return an image from the specified location. Throws a RuntimeException if
+     * the image cannot be located.
      *
      * @param subdir The position of the directory, e.g. 'layer'
@@ -87,5 +88,5 @@
         if (icon == null) {
             String ext = name.indexOf('.') != -1 ? "" : ".???";
-            throw new NullPointerException(tr(
+            throw new RuntimeException(tr(
                     "Fatal: failed to locate image ''{0}''. This is a serious configuration problem. JOSM will stop working.",
                     name+ext));
@@ -128,4 +129,8 @@
     public static ImageIcon getIfAvailable(Collection<String> dirs, String id, String subdir, String name, File archive, boolean sanitize) {
         return getIfAvailable(dirs, id, subdir, name, archive, null, sanitize);
+    }
+
+    public static ImageIcon getIfAvailable(Collection<String> dirs, String id, String subdir, String name, File archive, Dimension dim, boolean sanitize) {
+        return getIfAvailable(dirs, id, subdir, name, archive, dim, null, sanitize);
     }
 
@@ -144,15 +149,23 @@
      *                  part of the dimension can be -1. Then it will scale the width
      *                  in the same way as the height. (And the other way around.)
+     * @param maxSize   The maximum size of the image. It will shrink the image if necessary, and
+     *                  keep the aspect ratio. The given width or height can be -1 which means this
+     *                  direction is not bounded.
+     *                  If this parameter has a non-null value, the parameter 'dim' will be ignored.
      * @param sanitize  If the image should be repainted to a new BufferedImage to work
      *                  around certain issues.
      */
-    public static ImageIcon getIfAvailable(Collection<String> dirs, String id, String subdir, String name, File archive, Dimension dim, boolean sanitize) {
+    public static ImageIcon getIfAvailable(Collection<String> dirs, String id, String subdir, String name,
+            File archive, Dimension dim, Dimension maxSize, boolean sanitize) {
         ImageResource ir = getIfAvailableImpl(dirs, id, subdir, name, archive);
         if (ir == null)
             return null;
-        return ir.getImageIcon(dim == null ? ImageResource.DEFAULT_DIMENSION : dim, sanitize);
-    }
-
-    private static ImageResource getIfAvailableImpl(Collection<String> dirs, String id, String subdir, String name, File archive) {
+        if (maxSize != null)
+            return ir.getImageIconBounded(maxSize, sanitize);
+        else
+            return ir.getImageIcon(dim == null ? ImageResource.DEFAULT_DIMENSION : dim, sanitize);
+    }
+
+    static ImageResource getIfAvailableImpl(Collection<String> dirs, String id, String subdir, String name, File archive) {
         if (name == null)
             return null;
Index: trunk/src/org/openstreetmap/josm/tools/ImageRequest.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/ImageRequest.java	(revision 4711)
+++ trunk/src/org/openstreetmap/josm/tools/ImageRequest.java	(revision 4712)
@@ -27,4 +27,6 @@
     protected int width = -1;
     protected int height = -1;
+    protected int maxWidth = -1;
+    protected int maxHeight = -1;
     protected boolean sanitize;
     protected boolean required = true;
@@ -65,4 +67,14 @@
     }
 
+    public ImageRequest setMaxWidth(int maxWidth) {
+        this.maxWidth = maxWidth;
+        return this;
+    }
+
+    public ImageRequest setMaxHeight(int maxHeight) {
+        this.maxHeight = maxHeight;
+        return this;
+    }
+
     public ImageRequest setSanitize(boolean sanitize) {
         this.sanitize = sanitize;
@@ -76,10 +88,16 @@
 
     public ImageIcon get() {
-        ImageIcon icon = ImageProvider.getIfAvailable(dirs, id, subdir, name, archive, new Dimension(width, height), sanitize);
-        if (required && icon == null) {
-            String ext = name.indexOf('.') != -1 ? "" : ".???";
-            throw new NullPointerException(tr("Fatal: failed to locate image ''{0}''. This is a serious configuration problem. JOSM will stop working.", name + ext));
+        ImageResource ir = ImageProvider.getIfAvailableImpl(dirs, id, subdir, name, archive);
+        if (ir == null) {
+            if (required) {
+                String ext = name.indexOf('.') != -1 ? "" : ".???";
+                throw new RuntimeException(tr("Fatal: failed to locate image ''{0}''. This is a serious configuration problem. JOSM will stop working.", name + ext));
+            } else
+                return null;
         }
-        return icon;
+        if (maxWidth != -1 || maxHeight != -1)
+            return ir.getImageIconBounded(new Dimension(maxWidth, maxHeight), sanitize);
+        else 
+            return ir.getImageIcon(new Dimension(width, height), sanitize);
     }
     
Index: trunk/src/org/openstreetmap/josm/tools/ImageResource.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/ImageResource.java	(revision 4711)
+++ trunk/src/org/openstreetmap/josm/tools/ImageResource.java	(revision 4712)
@@ -62,4 +62,6 @@
      */
     public ImageIcon getImageIcon(Dimension dim, boolean sanitized) {
+        if (dim.width < -1 || dim.width == 0 || dim.height < -1 || dim.height == 0)
+            throw new IllegalArgumentException();
         ImageWrapper iw = imgCache.get(dim);
         if (iw != null) {
@@ -94,3 +96,48 @@
         }
     }
+
+    /**
+     * Get image icon with a certain maximum size. The image is scaled down
+     * to fit maximum dimensions. (Keeps aspect ratio)
+     *
+     * @param maxSize The maximum size. One of the dimensions (widht or height) can be -1,
+     * which means it is not bounded.
+     */
+    public ImageIcon getImageIconBounded(Dimension maxSize, boolean sanitized) {
+        if (maxSize.width < -1 || maxSize.width == 0 || maxSize.height < -1 || maxSize.height == 0)
+            throw new IllegalArgumentException();
+        float realWidth;
+        float realHeight;
+        if (svg != null) {
+            realWidth = svg.getWidth();
+            realHeight = svg.getHeight();
+        } else {
+            ImageWrapper base = imgCache.get(DEFAULT_DIMENSION);
+            if (base == null) throw new AssertionError();
+            ImageIcon icon = new ImageIcon(base.img);
+            realWidth = icon.getIconWidth();
+            realHeight = icon.getIconHeight();
+        }
+        int maxWidth = maxSize.width;
+        int maxHeight = maxSize.height;
+
+        if (realWidth <= maxWidth) {
+            maxWidth = -1;
+        }
+        if (realHeight <= maxHeight) {
+            maxHeight = -1;
+        }
+
+        if (maxWidth == -1 && maxHeight == -1)
+            return getImageIcon(DEFAULT_DIMENSION, sanitized);
+        else if (maxWidth == -1)
+            return getImageIcon(new Dimension(-1, maxHeight), sanitized);
+        else if (maxHeight == -1)
+            return getImageIcon(new Dimension(maxWidth, -1), sanitized);
+        else
+            if (realWidth / maxWidth > realHeight / maxHeight)
+                return getImageIcon(new Dimension(maxWidth, -1), sanitized);
+            else
+                return getImageIcon(new Dimension(-1, maxHeight), sanitized);
+   }
 }
