Index: gui/dialogs/NotesDialog.java
===================================================================
--- gui/dialogs/NotesDialog.java	(revision 10321)
+++ gui/dialogs/NotesDialog.java	(working copy)
@@ -61,17 +61,17 @@
     public static final ImageIcon ICON_OPEN = ImageProvider.get("dialogs/notes", "note_open");
     /** 16x16 icon for unresolved notes */
     public static final ImageIcon ICON_OPEN_SMALL =
-            new ImageIcon(ICON_OPEN.getImage().getScaledInstance(ICON_SMALL_SIZE, ICON_SMALL_SIZE, Image.SCALE_SMOOTH));
+            new ImageProvider("dialogs/notes", "note_open").setSize(ICON_SMALL_SIZE, ICON_SMALL_SIZE).get();
     /** 24x24 icon for resolved notes */
     public static final ImageIcon ICON_CLOSED = ImageProvider.get("dialogs/notes", "note_closed");
     /** 16x16 icon for resolved notes */
     public static final ImageIcon ICON_CLOSED_SMALL =
-            new ImageIcon(ICON_CLOSED.getImage().getScaledInstance(ICON_SMALL_SIZE, ICON_SMALL_SIZE, Image.SCALE_SMOOTH));
+            new ImageProvider("dialogs/notes", "note_closed").setSize(ICON_SMALL_SIZE, ICON_SMALL_SIZE).get();
     /** 24x24 icon for new notes */
     public static final ImageIcon ICON_NEW = ImageProvider.get("dialogs/notes", "note_new");
     /** 16x16 icon for new notes */
     public static final ImageIcon ICON_NEW_SMALL =
-            new ImageIcon(ICON_NEW.getImage().getScaledInstance(ICON_SMALL_SIZE, ICON_SMALL_SIZE, Image.SCALE_SMOOTH));
+            new ImageProvider("dialogs/notes", "note_new").setSize(ICON_SMALL_SIZE, ICON_SMALL_SIZE).get();
     /** Icon for note comments */
     public static final ImageIcon ICON_COMMENT = ImageProvider.get("dialogs/notes", "note_comment");
 
Index: gui/dialogs/ToggleDialog.java
===================================================================
--- gui/dialogs/ToggleDialog.java	(revision 10321)
+++ gui/dialogs/ToggleDialog.java	(working copy)
@@ -33,6 +33,7 @@
 import javax.swing.AbstractAction;
 import javax.swing.BorderFactory;
 import javax.swing.ButtonGroup;
+import javax.swing.ImageIcon;
 import javax.swing.JButton;
 import javax.swing.JCheckBoxMenuItem;
 import javax.swing.JComponent;
@@ -503,7 +504,8 @@
             add(lblMinimized);
 
             // scale down the dialog icon
-            lblTitle = new JLabel("", new ImageProvider("dialogs", iconName).setWidth(16).get(), JLabel.TRAILING);
+            ImageIcon icon = new ImageProvider("dialogs", iconName).setSize(ImageProvider.ImageSizes.SMALLICON).get();
+            lblTitle = new JLabel("", icon, JLabel.TRAILING);
             lblTitle.setIconTextGap(8);
 
             JPanel conceal = new JPanel();
@@ -540,7 +542,7 @@
 
             // show the pref button if applicable
             if (preferenceClass != null) {
-                JButton pref = new JButton(new ImageProvider("preference").setWidth(16).get());
+                JButton pref = new JButton(new ImageProvider("preference").setSize(ImageProvider.ImageSizes.SMALLICON).get());
                 pref.setToolTipText(tr("Open preferences for this panel"));
                 pref.setBorder(BorderFactory.createEmptyBorder());
                 pref.addActionListener(
Index: gui/io/SaveLayersDialog.java
===================================================================
--- gui/io/SaveLayersDialog.java	(revision 10321)
+++ gui/io/SaveLayersDialog.java	(working copy)
@@ -381,10 +381,10 @@
     }
 
     final class SaveAndProceedAction extends AbstractAction implements PropertyChangeListener {
-        private static final int ICON_SIZE = 24;
         private static final String BASE_ICON = "BASE_ICON";
         private final transient Image save = ImageProvider.get("save").getImage();
         private final transient Image upld = ImageProvider.get("upload").getImage();
+        private final transient int ICON_SIZE = save.getWidth(null);
         private final transient Image saveDis = new BufferedImage(ICON_SIZE, ICON_SIZE, BufferedImage.TYPE_4BYTE_ABGR);
         private final transient Image upldDis = new BufferedImage(ICON_SIZE, ICON_SIZE, BufferedImage.TYPE_4BYTE_ABGR);
 
Index: gui/mappaint/MapPaintStyles.java
===================================================================
--- gui/mappaint/MapPaintStyles.java	(revision 10321)
+++ gui/mappaint/MapPaintStyles.java	(working copy)
@@ -146,7 +146,7 @@
      */
     public static ImageIcon getIcon(IconReference ref, int width, int height) {
         final String namespace = ref.source.getPrefName();
-        ImageIcon i = getIconProvider(ref, false).setWidth(width).setHeight(height).get();
+        ImageIcon i = getIconProvider(ref, false).setSize(width, height).get();
         if (i == null) {
             Main.warn("Mappaint style \""+namespace+"\" ("+ref.source.getDisplayString()+") icon \"" + ref.iconName + "\" not found.");
             return null;
Index: gui/preferences/PreferenceTabbedPane.java
===================================================================
--- gui/preferences/PreferenceTabbedPane.java	(revision 10321)
+++ gui/preferences/PreferenceTabbedPane.java	(working copy)
@@ -509,10 +509,10 @@
                 if (expert || !tps.isExpert()) {
                     // Get icon
                     String iconName = tps.getIconName();
-                    ImageIcon icon = iconName != null && !iconName.isEmpty() ? ImageProvider.get("preferences", iconName) : null;
-                    // See #6985 - Force icons to be 48x48 pixels
-                    if (icon != null && (icon.getIconHeight() != 48 || icon.getIconWidth() != 48)) {
-                        icon = new ImageIcon(icon.getImage().getScaledInstance(48, 48, Image.SCALE_DEFAULT));
+                    ImageIcon icon = null;
+
+                    if(iconName != null && !iconName.isEmpty()) {
+                        icon = new ImageProvider("preferences", iconName).setSize(ImageProvider.ImageSizes.SETTINGS_TAB).get();
                     }
                     if (settingsInitialized.contains(tps)) {
                         // If it has been initialized, add corresponding tab(s)
Index: gui/SideButton.java
===================================================================
--- gui/SideButton.java	(revision 10321)
+++ gui/SideButton.java	(working copy)
@@ -25,7 +25,7 @@
  * @since 744
  */
 public class SideButton extends JButton implements Destroyable {
-    private static final int iconHeight = ImageProvider.ImageSizes.SIDEBUTTON.getImageSize();
+    private static final int iconHeight = ImageProvider.ImageSizes.SIDEBUTTON.getVirtualHeight();
 
     private transient PropertyChangeListener propertyChangeListener;
 
@@ -60,7 +60,8 @@
      */
     public SideButton(Action action, String imagename) {
         super(action);
-        setIcon(getScaledImage(ImageProvider.get("dialogs", imagename).getImage()));
+        Icon icon = new ImageProvider("dialogs", imagename).setHeight(iconHeight).get();
+        setIcon(icon);
         doStyle();
     }
 
@@ -91,7 +92,7 @@
      */
     private static ImageIcon getScaledImage(Image im) {
         int newWidth = im.getWidth(null) *  iconHeight / im.getHeight(null);
-        return new ImageIcon(im.getScaledInstance(newWidth, iconHeight, Image.SCALE_SMOOTH));
+        return ImageProvider.getScaledIcon(im, newWidth, iconHeight);
     }
 
     private void doStyle() {
Index: gui/SplashScreen.java
===================================================================
--- gui/SplashScreen.java	(revision 10321)
+++ gui/SplashScreen.java	(working copy)
@@ -8,7 +8,6 @@
 import java.awt.Dimension;
 import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
-import java.awt.Image;
 import java.awt.Insets;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
@@ -17,7 +16,6 @@
 import java.util.concurrent.CopyOnWriteArrayList;
 
 import javax.swing.BorderFactory;
-import javax.swing.ImageIcon;
 import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
@@ -69,7 +67,7 @@
         contentPane.add(innerContentPane);
 
         // Add the logo
-        JLabel logo = new JLabel(new ImageIcon(ImageProvider.get("logo.svg").getImage().getScaledInstance(128, 129, Image.SCALE_SMOOTH)));
+        JLabel logo = new JLabel(new ImageProvider("logo.svg").setSize(ImageProvider.ImageSizes.SPLASH_LOGO).get());
         GridBagConstraints gbc = new GridBagConstraints();
         gbc.gridheight = 2;
         gbc.insets = new Insets(0, 0, 0, 70);
Index: gui/widgets/TextContextualPopupMenu.java
===================================================================
--- gui/widgets/TextContextualPopupMenu.java	(revision 10321)
+++ gui/widgets/TextContextualPopupMenu.java	(working copy)
@@ -179,7 +179,7 @@
             JMenuItem mi = new JMenuItem(action);
             mi.setText(label);
             if (iconName != null && Main.pref.getBoolean("text.popupmenu.useicons", true)) {
-                ImageIcon icon = new ImageProvider(iconName).setWidth(16).get();
+                ImageIcon icon = new ImageProvider(iconName).setSize(ImageProvider.ImageSizes.SMALLICON).get();
                 if (icon != null) {
                     mi.setIcon(icon);
                 }
Index: io/session/GenericSessionExporter.java
===================================================================
--- io/session/GenericSessionExporter.java	(revision 10321)
+++ io/session/GenericSessionExporter.java	(working copy)
@@ -73,7 +73,7 @@
          * Constructs a new {@code LayerSaveAction}.
          */
         LayerSaveAction() {
-            putValue(SMALL_ICON, new ImageProvider("save").setWidth(16).get());
+            putValue(SMALL_ICON, new ImageProvider("save").setSize(ImageProvider.ImageSizes.SMALLICON).get());
             putValue(SHORT_DESCRIPTION, ((AbstractModifiableLayer) layer).requiresSaveToFile() ?
                     tr("Layer contains unsaved data - save to file.") :
                     tr("Layer does not contain unsaved data."));
Index: plugins/PluginInformation.java
===================================================================
--- plugins/PluginInformation.java	(revision 10321)
+++ plugins/PluginInformation.java	(working copy)
@@ -3,7 +3,7 @@
 
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.awt.Image;
+import java.awt.Dimension;
 import java.awt.image.BufferedImage;
 import java.io.File;
 import java.io.FileInputStream;
@@ -28,6 +28,7 @@
 
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.Version;
+import org.openstreetmap.josm.gui.util.GuiSizesHelper;
 import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.LanguageInfo;
 import org.openstreetmap.josm.tools.Utils;
@@ -84,7 +85,10 @@
     /** All manifest attributes. */
     public final Map<String, String> attr = new TreeMap<>();
 
-    private static final ImageIcon emptyIcon = new ImageIcon(new BufferedImage(24, 24, BufferedImage.TYPE_INT_ARGB));
+    private static final Dimension iconRealSize =
+            GuiSizesHelper.getDimensionDpiAdjusted(ImageProvider.ImageSizes.LARGEICON.getImageDimension());
+    private static final ImageIcon emptyIcon =
+            new ImageIcon(new BufferedImage(iconRealSize.width, iconRealSize.height, BufferedImage.TYPE_INT_ARGB));
 
     /**
      * Creates a plugin information object by reading the plugin information from
@@ -243,9 +247,9 @@
         if (iconPath != null) {
             if (file != null) {
                 // extract icon from the plugin jar file
-                icon = new ImageProvider(iconPath).setArchive(file).setMaxWidth(24).setMaxHeight(24).setOptional(true).get();
+                icon = new ImageProvider(iconPath).setArchive(file).setMaxSize(ImageProvider.ImageSizes.LARGEICON).setOptional(true).get();
             } else if (iconPath.startsWith("data:")) {
-                icon = new ImageProvider(iconPath).setMaxWidth(24).setMaxHeight(24).setOptional(true).get();
+                icon = new ImageProvider(iconPath).setMaxSize(ImageProvider.ImageSizes.LARGEICON).setOptional(true).get();
             }
         }
         canloadatruntime = Boolean.parseBoolean(attr.getValue("Plugin-Canloadatruntime"));
@@ -499,7 +503,7 @@
     public ImageIcon getScaledIcon() {
         if (icon == null)
             return emptyIcon;
-        return new ImageIcon(icon.getImage().getScaledInstance(24, 24, Image.SCALE_SMOOTH));
+        return ImageProvider.getScaledIcon(icon, ImageProvider.ImageSizes.LARGEICON);
     }
 
     @Override
Index: tools/ImageProvider.java
===================================================================
--- tools/ImageProvider.java	(revision 10321)
+++ tools/ImageProvider.java	(working copy)
@@ -68,6 +68,7 @@
 import org.openstreetmap.josm.gui.mappaint.styleelement.StyleElement;
 import org.openstreetmap.josm.gui.tagging.presets.TaggingPreset;
 import org.openstreetmap.josm.gui.tagging.presets.TaggingPresets;
+import org.openstreetmap.josm.gui.util.GuiSizesHelper;
 import org.openstreetmap.josm.io.CachedFile;
 import org.openstreetmap.josm.plugins.PluginHandler;
 import org.w3c.dom.Element;
@@ -144,13 +145,13 @@
         /** cursor icon size */
         CURSOR(Main.pref.getInteger("iconsize.cursor", 32)),
         /** cursor overlay icon size */
-        CURSOROVERLAY(CURSOR.imageSize),
+        CURSOROVERLAY(CURSOR),
         /** menu icon size */
-        MENU(SMALLICON.imageSize),
+        MENU(SMALLICON),
         /** menu icon size in popup menus
          * @since 8323
          */
-        POPUPMENU(LARGEICON.imageSize),
+        POPUPMENU(LARGEICON),
         /** Layer list icon size
          * @since 8323
          */
@@ -158,30 +159,66 @@
         /** Toolbar button icon size
          * @since 9253
          */
-        TOOLBAR(LARGEICON.imageSize),
+        TOOLBAR(LARGEICON),
         /** Side button maximum height
          * @since 9253
          */
         SIDEBUTTON(Main.pref.getInteger("iconsize.sidebutton", 20)),
+        /** Side button maximum height
+         * @since 9253
+         */
+        SETTINGS_TAB(Main.pref.getInteger("iconsize.settingstab", 48)),
         /**
          * The default image size
          * @since 9705
          */
-        DEFAULT(Main.pref.getInteger("iconsize.default", 24));
+        DEFAULT(Main.pref.getInteger("iconsize.default", 24)),
 
-        private final int imageSize;
+        /**
+         * Splash dialog logo size
+         * @since XXXX
+         */
+        SPLASH_LOGO(128, 129),
 
+        /**
+         * About dialog logo size
+         * @since XXXX
+         */
+        ABOUT_LOGO(256, 258);
+
+        private final int virtualWidth;
+        private final int virtualHeight;
+
         ImageSizes(int imageSize) {
-            this.imageSize = imageSize;
+            this.virtualWidth = imageSize;
+            this.virtualHeight = imageSize;
         }
 
+        ImageSizes(int width, int height) {
+            this.virtualWidth = width;
+            this.virtualHeight = height;
+        }
+
+        ImageSizes(ImageSizes that) {
+            this.virtualWidth = that.virtualWidth;
+            this.virtualHeight = that.virtualHeight;
+        }
+
         /**
-         * Returns the image size in pixels
-         * @return the image size in pixels
+         * Returns the image width in virtual pixels
+         * @return the image width in virtual pixels
+         */
+        public int getVirtualWidth() {
+            return virtualWidth;
+        }
+
+        /**
+         * Returns the image height in virtual pixels
+         * @return the image height in virtual pixels
          * @since 9705
          */
-        public int getImageSize() {
-            return imageSize;
+        public int getVirtualHeight() {
+            return virtualHeight;
         }
 
         /**
@@ -190,7 +227,7 @@
          * @since 9705
          */
         public Dimension getImageDimension() {
-            return new Dimension(imageSize, imageSize);
+            return new Dimension(virtualWidth, virtualHeight);
         }
     }
 
@@ -218,14 +255,14 @@
     protected File archive;
     /** directory inside the archive */
     protected String inArchiveDir;
-    /** width of the resulting image, -1 when original image data should be used */
-    protected int width = -1;
-    /** height of the resulting image, -1 when original image data should be used */
-    protected int height = -1;
-    /** maximum width of the resulting image, -1 for no restriction */
-    protected int maxWidth = -1;
-    /** maximum height of the resulting image, -1 for no restriction */
-    protected int maxHeight = -1;
+    /** virtual width of the resulting image, -1 when original image data should be used */
+    protected int virtualWidth = -1;
+    /** virtual height of the resulting image, -1 when original image data should be used */
+    protected int virtualHeight = -1;
+    /** virtual maximum width of the resulting image, -1 for no restriction */
+    protected int virtualMaxWidth = -1;
+    /** virtual maximum height of the resulting image, -1 for no restriction */
+    protected int virtualMaxHeight = -1;
     /** In case of errors do not throw exception but return <code>null</code> for missing image */
     protected boolean optional;
     /** <code>true</code> if warnings should be suppressed */
@@ -305,10 +342,10 @@
         this.name = image.name;
         this.archive = image.archive;
         this.inArchiveDir = image.inArchiveDir;
-        this.width = image.width;
-        this.height = image.height;
-        this.maxWidth = image.maxWidth;
-        this.maxHeight = image.maxHeight;
+        this.virtualWidth = image.virtualWidth;
+        this.virtualHeight = image.virtualHeight;
+        this.virtualMaxWidth = image.virtualMaxWidth;
+        this.virtualMaxHeight = image.virtualMaxHeight;
         this.optional = image.optional;
         this.suppressWarnings = image.suppressWarnings;
         this.additionalClassLoaders = image.additionalClassLoaders;
@@ -388,8 +425,8 @@
      * @return the current object, for convenience
      */
     public ImageProvider setSize(Dimension size) {
-        this.width = size.width;
-        this.height = size.height;
+        this.virtualWidth = size.width;
+        this.virtualHeight = size.height;
         return this;
     }
 
@@ -405,6 +442,12 @@
         return setSize(size.getImageDimension());
     }
 
+    public ImageProvider setSize(int width, int height) {
+        this.virtualWidth = width;
+        this.virtualHeight = height;
+        return this;
+    }
+
     /**
      * Set image width
      * @param width final width of the image
@@ -412,7 +455,7 @@
      * @see #setSize
      */
     public ImageProvider setWidth(int width) {
-        this.width = width;
+        this.virtualWidth = width;
         return this;
     }
 
@@ -423,7 +466,7 @@
      * @see #setSize
      */
     public ImageProvider setHeight(int height) {
-        this.height = height;
+        this.virtualHeight = height;
         return this;
     }
 
@@ -438,8 +481,8 @@
      * @return the current object, for convenience
      */
     public ImageProvider setMaxSize(Dimension maxSize) {
-        this.maxWidth = maxSize.width;
-        this.maxHeight = maxSize.height;
+        this.virtualMaxWidth = maxSize.width;
+        this.virtualMaxHeight = maxSize.height;
         return this;
     }
 
@@ -457,11 +500,11 @@
      * @see #setMaxSize(Dimension)
      */
     public ImageProvider resetMaxSize(Dimension maxSize) {
-        if (this.maxWidth == -1 || maxSize.width < this.maxWidth) {
-            this.maxWidth = maxSize.width;
+        if (this.virtualMaxWidth == -1 || maxSize.width < this.virtualMaxWidth) {
+            this.virtualMaxWidth = maxSize.width;
         }
-        if (this.maxHeight == -1 || maxSize.height < this.maxHeight) {
-            this.maxHeight = maxSize.height;
+        if (this.virtualMaxHeight == -1 || maxSize.height < this.virtualMaxHeight) {
+            this.virtualMaxHeight = maxSize.height;
         }
         return this;
     }
@@ -497,7 +540,7 @@
      * @see #setMaxSize
      */
     public ImageProvider setMaxWidth(int maxWidth) {
-        this.maxWidth = maxWidth;
+        this.virtualMaxWidth = maxWidth;
         return this;
     }
 
@@ -508,7 +551,7 @@
      * @see #setMaxSize
      */
     public ImageProvider setMaxHeight(int maxHeight) {
-        this.maxHeight = maxHeight;
+        this.virtualMaxHeight = maxHeight;
         return this;
     }
 
@@ -556,10 +599,10 @@
         ImageResource ir = getResource();
         if (ir == null)
             return null;
-        if (maxWidth != -1 || maxHeight != -1)
-            return ir.getImageIconBounded(new Dimension(maxWidth, maxHeight));
+        if (virtualMaxWidth != -1 || virtualMaxHeight != -1)
+            return ir.getImageIconBounded(new Dimension(virtualMaxWidth, virtualMaxHeight));
         else
-            return ir.getImageIcon(new Dimension(width, height));
+            return ir.getImageIcon(new Dimension(virtualWidth, virtualHeight));
     }
 
     /**
@@ -691,6 +734,35 @@
     }
 
     /**
+     * Scale image to imgSize dimensions. This method resizes image with respect to actual screen DPI.
+     *
+     * @param icon image to be resized
+     * @param imgSize target size of image
+     * @return new scaled image in real dimensions
+     */
+    public static ImageIcon getScaledIcon(ImageIcon icon, ImageSizes imgSize) {
+        Dimension size = imgSize.getImageDimension();
+        size = GuiSizesHelper.getDimensionDpiAdjusted(size);
+        return new ImageIcon(icon.getImage().getScaledInstance(size.width, size.height, Image.SCALE_SMOOTH));
+    }
+
+    /**
+     * Scale image to virtual dimensions. This util method is used to hide real sizes calculations.
+     * All other classes should use this method to resize images.
+     *
+     * @param im image to be resized
+     * @param virtualWidth target width of image in virtual pixels
+     * @param virtualHeight target height of image in virtual pixels
+     * @return new scaled image in real dimensions
+     */
+    public static ImageIcon getScaledIcon(Image im, int virtualWidth, int virtualHeight) {
+        int realWidth = GuiSizesHelper.getSizeDpiAdjusted(virtualWidth);
+        int realHeight = GuiSizesHelper.getSizeDpiAdjusted(virtualHeight);
+
+        return new ImageIcon(im.getScaledInstance(realWidth, realHeight, Image.SCALE_SMOOTH));
+    }
+
+    /**
      * {@code data:[<mediatype>][;base64],<data>}
      * @see <a href="http://tools.ietf.org/html/rfc2397">RFC2397</a>
      */
@@ -1332,14 +1404,14 @@
                     NodeElement nodeStyle = (NodeElement) style;
                     MapImage icon = nodeStyle.mapImage;
                     if (icon != null) {
-                        int backgroundWidth = iconSize.width;
-                        int backgroundHeight = iconSize.height;
-                        int iconWidth = icon.getWidth();
-                        int iconHeight = icon.getHeight();
-                        BufferedImage image = new BufferedImage(backgroundWidth, backgroundHeight,
+                        int backgroundRealWidth = GuiSizesHelper.getSizeDpiAdjusted(iconSize.width);
+                        int backgroundRealHeight = GuiSizesHelper.getSizeDpiAdjusted(iconSize.height);
+                        int iconRealWidth = icon.getWidth();
+                        int iconRealHeight = icon.getHeight();
+                        BufferedImage image = new BufferedImage(backgroundRealWidth, backgroundRealHeight,
                                 BufferedImage.TYPE_INT_ARGB);
-                        double scaleFactor = Math.min(backgroundWidth / (double) iconWidth, backgroundHeight
-                                / (double) iconHeight);
+                        double scaleFactor = Math.min(backgroundRealWidth / (double) iconRealWidth, backgroundRealHeight
+                                / (double) iconRealHeight);
                         BufferedImage iconImage = icon.getImage(false);
                         Image scaledIcon;
                         final int scaledWidth;
@@ -1346,17 +1418,17 @@
                         final int scaledHeight;
                         if (scaleFactor < 1) {
                             // Scale icon such that it fits on background.
-                            scaledWidth = (int) (iconWidth * scaleFactor);
-                            scaledHeight = (int) (iconHeight * scaleFactor);
+                            scaledWidth = (int) (iconRealWidth * scaleFactor);
+                            scaledHeight = (int) (iconRealHeight * scaleFactor);
                             scaledIcon = iconImage.getScaledInstance(scaledWidth, scaledHeight, Image.SCALE_SMOOTH);
                         } else {
                             // Use original size, don't upscale.
-                            scaledWidth = iconWidth;
-                            scaledHeight = iconHeight;
+                            scaledWidth = iconRealWidth;
+                            scaledHeight = iconRealHeight;
                             scaledIcon = iconImage;
                         }
-                        image.getGraphics().drawImage(scaledIcon, (backgroundWidth - scaledWidth) / 2,
-                                (backgroundHeight - scaledHeight) / 2, null);
+                        image.getGraphics().drawImage(scaledIcon, (backgroundRealWidth - scaledWidth) / 2,
+                                (backgroundRealHeight - scaledHeight) / 2, null);
 
                         return new ImageIcon(image);
                     }
@@ -1393,35 +1465,37 @@
      * @return an image from the given SVG data at the desired dimension.
      */
     public static BufferedImage createImageFromSvg(SVGDiagram svg, Dimension dim) {
-        float realWidth = svg.getWidth();
-        float realHeight = svg.getHeight();
-        int width = Math.round(realWidth);
-        int height = Math.round(realHeight);
-        Double scaleX = null, scaleY = null;
+        float sourceWidth = svg.getWidth();
+        float sourceHeight = svg.getHeight();
+        int realWidth = Math.round(GuiSizesHelper.getSizeDpiAdjusted(sourceWidth));
+        int realHeight = Math.round(GuiSizesHelper.getSizeDpiAdjusted(sourceHeight));
+        Double scaleX, scaleY;
         if (dim.width != -1) {
-            width = dim.width;
-            scaleX = (double) width / realWidth;
+            realWidth = dim.width;
+            scaleX = (double) realWidth / sourceWidth;
             if (dim.height == -1) {
                 scaleY = scaleX;
-                height = (int) Math.round(realHeight * scaleY);
+                realHeight = (int) Math.round(sourceHeight * scaleY);
             } else {
-                height = dim.height;
-                scaleY = (double) height / realHeight;
+                realHeight = dim.height;
+                scaleY = (double) realHeight / sourceHeight;
             }
         } else if (dim.height != -1) {
-            height = dim.height;
-            scaleX = scaleY = (double) height / realHeight;
-            width = (int) Math.round(realWidth * scaleX);
+            realHeight = dim.height;
+            scaleX = scaleY = (double) realHeight / sourceHeight;
+            realWidth = (int) Math.round(sourceWidth * scaleX);
         }
-        if (width == 0 || height == 0) {
+        else {
+            scaleX = scaleY = (double) realHeight / sourceHeight;
+        }
+
+        if (realWidth == 0 || realHeight == 0) {
             return null;
         }
-        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+        BufferedImage img = new BufferedImage(realWidth, realHeight, BufferedImage.TYPE_INT_ARGB);
         Graphics2D g = img.createGraphics();
-        g.setClip(0, 0, width, height);
-        if (scaleX != null && scaleY != null) {
-            g.scale(scaleX, scaleY);
-        }
+        g.setClip(0, 0, realWidth, realHeight);
+        g.scale(scaleX, scaleY);
         g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
         try {
             synchronized (getSvgUniverse()) {
Index: tools/ImageResource.java
===================================================================
--- tools/ImageResource.java	(revision 10321)
+++ tools/ImageResource.java	(working copy)
@@ -13,6 +13,7 @@
 import javax.swing.ImageIcon;
 
 import com.kitfox.svg.SVGDiagram;
+import org.openstreetmap.josm.gui.util.GuiSizesHelper;
 
 /**
  * Holds data for one particular image.
@@ -49,9 +50,31 @@
     public ImageResource(Image img) {
         CheckParameterUtil.ensureParameterNotNull(img);
         this.baseImage = img;
+
+        img = scaleBaseImageIfNeeded(img);
+
         imgCache.put(DEFAULT_DIMENSION, img);
     }
 
+    /** Scale image according to screen DPI if needed.
+     *
+     * @param img an image loaded from file (it's width and height are virtual pixels)
+     * @return original img if virtual size is the same as real size or new image resized to real pixels
+     */
+    private static Image scaleBaseImageIfNeeded(Image img) {
+        int imgWidth = img.getWidth(null);
+        int imgHeight = img.getHeight(null);
+        int realWidth = GuiSizesHelper.getSizeDpiAdjusted(imgWidth);
+        int realHeight = GuiSizesHelper.getSizeDpiAdjusted(imgHeight);
+        if (realWidth != -1 && realHeight != -1 && imgWidth != realWidth && imgHeight != realHeight) {
+            Image realImage = img.getScaledInstance(realWidth, realHeight, Image.SCALE_SMOOTH);
+            BufferedImage bimg = new BufferedImage(realWidth, realHeight, BufferedImage.TYPE_INT_ARGB);
+            bimg.getGraphics().drawImage(realImage, 0, 0, null);
+            img = bimg;
+        }
+        return img;
+    }
+
     /**
      * Constructs a new {@code ImageResource} from SVG data.
      * @param svg SVG data
@@ -87,9 +110,12 @@
      * @since 7693
      */
     public void getImageIcon(AbstractAction a) {
-        ImageIcon icon = getImageIconBounded(ImageProvider.ImageSizes.SMALLICON.getImageDimension());
+        Dimension iconDimension = ImageProvider.ImageSizes.SMALLICON.getImageDimension();
+        ImageIcon icon = getImageIconBounded(iconDimension);
         a.putValue(Action.SMALL_ICON, icon);
-        icon = getImageIconBounded(ImageProvider.ImageSizes.LARGEICON.getImageDimension());
+
+        iconDimension = ImageProvider.ImageSizes.LARGEICON.getImageDimension();
+        icon = getImageIconBounded(iconDimension);
         a.putValue(Action.LARGE_ICON_KEY, icon);
     }
 
@@ -108,7 +134,8 @@
             return new ImageIcon(img);
         }
         if (svg != null) {
-            BufferedImage bimg = ImageProvider.createImageFromSvg(svg, dim);
+            Dimension realDim = GuiSizesHelper.getDimensionDpiAdjusted(dim);
+            BufferedImage bimg = ImageProvider.createImageFromSvg(svg, realDim);
             if (bimg == null) {
                 return null;
             }
@@ -122,19 +149,19 @@
         } else {
             if (baseImage == null) throw new AssertionError();
 
-            int width = dim.width;
-            int height = dim.height;
+            int realWidth = GuiSizesHelper.getSizeDpiAdjusted(dim.width);
+            int realHeight = GuiSizesHelper.getSizeDpiAdjusted(dim.height);
             ImageIcon icon = new ImageIcon(baseImage);
-            if (width == -1 && height == -1) {
-                width = icon.getIconWidth();
-                height = icon.getIconHeight();
-            } else if (width == -1) {
-                width = Math.max(1, icon.getIconWidth() * height / icon.getIconHeight());
-            } else if (height == -1) {
-                height = Math.max(1, icon.getIconHeight() * width / icon.getIconWidth());
+            if (realWidth == -1 && realHeight == -1) {
+                realWidth = GuiSizesHelper.getSizeDpiAdjusted(icon.getIconWidth());
+                realHeight = GuiSizesHelper.getSizeDpiAdjusted(icon.getIconHeight());
+            } else if (realWidth == -1) {
+                realWidth = Math.max(1, icon.getIconWidth() * realHeight / icon.getIconHeight());
+            } else if (realHeight == -1) {
+                realHeight = Math.max(1, icon.getIconHeight() * realWidth / icon.getIconWidth());
             }
-            Image i = icon.getImage().getScaledInstance(width, height, Image.SCALE_SMOOTH);
-            BufferedImage bimg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+            Image i = icon.getImage().getScaledInstance(realWidth, realHeight, Image.SCALE_SMOOTH);
+            BufferedImage bimg = new BufferedImage(realWidth, realHeight, BufferedImage.TYPE_INT_ARGB);
             bimg.getGraphics().drawImage(i, 0, 0, null);
             if (overlayInfo != null) {
                 for (ImageOverlay o : overlayInfo) {
@@ -157,22 +184,22 @@
     public ImageIcon getImageIconBounded(Dimension maxSize) {
         if (maxSize.width < -1 || maxSize.width == 0 || maxSize.height < -1 || maxSize.height == 0)
             throw new IllegalArgumentException(maxSize+" is invalid");
-        float realWidth;
-        float realHeight;
+        float sourceWidth;
+        float sourceHeight;
         int maxWidth = maxSize.width;
         int maxHeight = maxSize.height;
         if (svg != null) {
-            realWidth = svg.getWidth();
-            realHeight = svg.getHeight();
+            sourceWidth = svg.getWidth();
+            sourceHeight = svg.getHeight();
         } else {
             if (baseImage == null) throw new AssertionError();
             ImageIcon icon = new ImageIcon(baseImage);
-            realWidth = icon.getIconWidth();
-            realHeight = icon.getIconHeight();
-            if (realWidth <= maxWidth) {
+            sourceWidth = icon.getIconWidth();
+            sourceHeight = icon.getIconHeight();
+            if (sourceWidth <= maxWidth) {
                 maxWidth = -1;
             }
-            if (realHeight <= maxHeight) {
+            if (sourceHeight <= maxHeight) {
                 maxHeight = -1;
             }
         }
@@ -183,7 +210,7 @@
             return getImageIcon(new Dimension(-1, maxHeight));
         else if (maxHeight == -1)
             return getImageIcon(new Dimension(maxWidth, -1));
-        else if (realWidth / maxWidth > realHeight / maxHeight)
+        else if (sourceWidth / maxWidth > sourceHeight / maxHeight)
             return getImageIcon(new Dimension(maxWidth, -1));
         else
             return getImageIcon(new Dimension(-1, maxHeight));
Index: gui/util/GuiSizesHelper.java
===================================================================
--- gui/util/GuiSizesHelper.java	(nonexistent)
+++ gui/util/GuiSizesHelper.java	(working copy)
@@ -0,0 +1,65 @@
+package org.openstreetmap.josm.gui.util;
+
+import java.awt.*;
+
+public class GuiSizesHelper {
+    private static int screenDPI = -1;
+
+    private static int getScreenDPI() {
+        if (screenDPI == -1) {
+            synchronized (GuiHelper.class) {
+                if (screenDPI == -1) {
+                    screenDPI = Toolkit.getDefaultToolkit().getScreenResolution();
+                }
+            }
+        }
+        return screenDPI;
+    }
+
+    /**
+     * Returns coefficient of monitor pixel density. All hardcoded sizes must be multiplied by this value.
+     *
+     * @return float value. 1 - means standard monitor, 2 and high - "retina" display.
+     * @since XXX
+     */
+    public static float getPixelDensity() {
+        int pixelPerInch = getScreenDPI();
+        return (float) (pixelPerInch / 96.);
+    }
+
+    public static boolean isHiDPI() {
+        return getPixelDensity() >= 2f;
+    }
+
+    public static int getSizeDpiAdjusted(int size) {
+        if (size <= 0) return size;
+        int pixelPerInch = getScreenDPI();
+        return size * pixelPerInch / 96;
+    }
+
+    public static float getSizeDpiAdjusted(float size) {
+        if (size <= 0f) return size;
+        int pixelPerInch = getScreenDPI();
+        return size * pixelPerInch / 96;
+    }
+
+    public static double getSizeDpiAdjusted(double size) {
+        if (size <= 0d) return size;
+        int pixelPerInch = getScreenDPI();
+        return size * pixelPerInch / 96;
+    }
+
+    public static Dimension getDimensionDpiAdjusted(Dimension dim) {
+        int pixelPerInch = getScreenDPI();
+        int width = dim.width, height = dim.height;
+        if (dim.width > 0) {
+            width = dim.width * pixelPerInch / 96;
+        }
+
+        if (dim.height > 0) {
+            height = dim.height * pixelPerInch / 96;
+        }
+
+        return new Dimension(width, height);
+    }
+}
