Changeset 12722 in josm


Ignore:
Timestamp:
2017-09-04T18:52:06+02:00 (7 years ago)
Author:
bastiK
Message:

see #9995 - fix blurry GUI-icons and map view for Java 9 HiDPI mode

Location:
trunk/src/org/openstreetmap/josm
Files:
1 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java

    r12620 r12722  
    8282import org.openstreetmap.josm.tools.JosmRuntimeException;
    8383import org.openstreetmap.josm.tools.Logging;
     84import org.openstreetmap.josm.tools.HiDPISupport;
    8485import org.openstreetmap.josm.tools.Utils;
    8586import org.openstreetmap.josm.tools.bugreport.BugReport;
     
    417418                }
    418419            } else {
    419                 TexturePaint texture = new TexturePaint(fillImage.getImage(disabled),
     420                Image img = fillImage.getImage(disabled);
     421                // TexturePaint requires BufferedImage -> get base image from
     422                // possible multi-resolution image
     423                img = HiDPISupport.getBaseImage(img);
     424                TexturePaint texture = new TexturePaint((BufferedImage) img,
    420425                        new Rectangle(0, 0, fillImage.getWidth(), fillImage.getHeight()));
    421426                g.setPaint(texture);
     
    657662        double startOffset = computeStartOffset(phase, repeat);
    658663
    659         BufferedImage image = pattern.getImage(disabled);
     664        Image image = pattern.getImage(disabled);
    660665
    661666        path.visitClippedLine(repeat, (inLineOffset, start, end, startIsOldEnd) -> {
     
    11501155        displayText(() -> {
    11511156            AffineTransform defaultTransform = g.getTransform();
    1152             g.setTransform(at);
     1157            g.transform(at);
    11531158            g.setFont(text.font);
    11541159            g.drawString(name, 0, 0);
  • trunk/src/org/openstreetmap/josm/gui/MapView.java

    r12651 r12722  
    99import java.awt.Point;
    1010import java.awt.Rectangle;
     11import java.awt.Shape;
    1112import java.awt.event.ComponentAdapter;
    1213import java.awt.event.ComponentEvent;
     
    1516import java.awt.event.MouseEvent;
    1617import java.awt.event.MouseMotionListener;
     18import java.awt.geom.AffineTransform;
    1719import java.awt.geom.Area;
    1820import java.awt.image.BufferedImage;
     
    511513
    512514    private void drawMapContent(Graphics g) {
     515        // In HiDPI-mode, the Graphics g will have a transform that scales
     516        // everything by a factor of 2.0 or so. At the same time, the value returned
     517        // by getWidth()/getHeight will be reduced by that factor.
     518        //
     519        // This would work as intended, if we were to draw directly on g. But
     520        // with a temporary buffer image, we need to move the scale transform to
     521        // the Graphics of the buffer image and (in the end) transfer the content
     522        // of the temporary buffer pixel by pixel onto g, without scaling.
     523        // (Otherwise, we would upscale a small buffer image and the result would be
     524        // blurry, with 2x2 pixel blocks.)
     525        Graphics2D gg = (Graphics2D) g;
     526        AffineTransform trOrig = gg.getTransform();
     527        double uiScaleX = gg.getTransform().getScaleX();
     528        double uiScaleY = gg.getTransform().getScaleY();
     529        // width/height in full-resolution screen pixels
     530        int width = (int) Math.round(getWidth() * uiScaleX);
     531        int height = (int) Math.round(getHeight() * uiScaleY);
     532        // This transformation corresponds to the original transformation of g,
     533        // except for the translation part. It will be applied to the temporary
     534        // buffer images.
     535        AffineTransform trDef = AffineTransform.getScaleInstance(uiScaleX, uiScaleY);
     536        // The goal is to create the temporary image at full pixel resolution,
     537        // so scale up the clip shape
     538        Shape scaledClip = trDef.createTransformedShape(g.getClip());
     539
    513540        List<Layer> visibleLayers = layerManager.getVisibleLayersInZOrder();
    514541
     
    529556                && nonChangedLayers.equals(visibleLayers.subList(0, nonChangedLayers.size()));
    530557
    531         if (null == offscreenBuffer || offscreenBuffer.getWidth() != getWidth() || offscreenBuffer.getHeight() != getHeight()) {
    532             offscreenBuffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_3BYTE_BGR);
    533         }
    534 
    535         Graphics2D tempG = offscreenBuffer.createGraphics();
    536         tempG.setClip(g.getClip());
     558        if (null == offscreenBuffer || offscreenBuffer.getWidth() != width || offscreenBuffer.getHeight() != height) {
     559            offscreenBuffer = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
     560        }
    537561
    538562        if (!canUseBuffer || nonChangedLayersBuffer == null) {
    539563            if (null == nonChangedLayersBuffer
    540                     || nonChangedLayersBuffer.getWidth() != getWidth() || nonChangedLayersBuffer.getHeight() != getHeight()) {
    541                 nonChangedLayersBuffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_3BYTE_BGR);
     564                    || nonChangedLayersBuffer.getWidth() != width || nonChangedLayersBuffer.getHeight() != height) {
     565                nonChangedLayersBuffer = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
    542566            }
    543567            Graphics2D g2 = nonChangedLayersBuffer.createGraphics();
    544             g2.setClip(g.getClip());
     568            g2.setClip(scaledClip);
     569            g2.setTransform(trDef);
    545570            g2.setColor(PaintColors.getBackgroundColor());
    546             g2.fillRect(0, 0, getWidth(), getHeight());
     571            g2.fillRect(0, 0, width, height);
    547572
    548573            for (int i = 0; i < nonChangedLayersCount; i++) {
     
    553578            if (nonChangedLayers.size() != nonChangedLayersCount) {
    554579                Graphics2D g2 = nonChangedLayersBuffer.createGraphics();
    555                 g2.setClip(g.getClip());
     580                g2.setClip(scaledClip);
     581                g2.setTransform(trDef);
    556582                for (int i = nonChangedLayers.size(); i < nonChangedLayersCount; i++) {
    557583                    paintLayer(visibleLayers.get(i), g2);
     
    565591        lastClipBounds = g.getClipBounds();
    566592
     593        Graphics2D tempG = offscreenBuffer.createGraphics();
     594        tempG.setClip(scaledClip);
     595        tempG.setTransform(new AffineTransform());
    567596        tempG.drawImage(nonChangedLayersBuffer, 0, 0, null);
     597        tempG.setTransform(trDef);
    568598
    569599        for (int i = nonChangedLayersCount; i < visibleLayers.size(); i++) {
     
    572602
    573603        try {
    574             drawTemporaryLayers(tempG, getLatLonBounds(g.getClipBounds()));
     604            drawTemporaryLayers(tempG, getLatLonBounds(new Rectangle(
     605                    (int) Math.round(g.getClipBounds().x * uiScaleX),
     606                    (int) Math.round(g.getClipBounds().y * uiScaleY))));
    575607        } catch (JosmRuntimeException | IllegalArgumentException | IllegalStateException e) {
    576608            BugReport.intercept(e).put("temporaryLayers", temporaryLayers).warn();
     
    597629
    598630        try {
    599             g.drawImage(offscreenBuffer, 0, 0, null);
     631            gg.setTransform(new AffineTransform(1, 0, 0, 1, trOrig.getTranslateX(), trOrig.getTranslateY()));
     632            gg.drawImage(offscreenBuffer, 0, 0, null);
    600633        } catch (ClassCastException e) {
    601634            // See #11002 and duplicate tickets. On Linux with Java >= 8 Many users face this error here:
     
    623656            // But the application seems to work fine after, so let's just log the error
    624657            Logging.error(e);
     658        } finally {
     659            gg.setTransform(trOrig);
    625660        }
    626661    }
  • trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/AreaElement.java

    r12285 r12722  
    33
    44import java.awt.Color;
     5import java.awt.Image;
     6import java.awt.image.BufferedImage;
    57import java.util.Objects;
    68
     
    1618import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.IconReference;
    1719import org.openstreetmap.josm.tools.CheckParameterUtil;
     20import org.openstreetmap.josm.tools.HiDPISupport;
    1821import org.openstreetmap.josm.tools.Utils;
    1922
     
    7982        if (iconRef != null) {
    8083            fillImage = new MapImage(iconRef.iconName, iconRef.source, false);
    81 
    82             color = new Color(fillImage.getImage(false).getRGB(
     84            Image img = fillImage.getImage(false);
     85            // get base image from possible multi-resolution image, so we can
     86            // cast to BufferedImage and get pixel value at the center of the image
     87            img = HiDPISupport.getBaseImage(img);
     88            color = new Color(((BufferedImage) img).getRGB(
    8389                    fillImage.getWidth() / 2, fillImage.getHeight() / 2)
    8490            );
  • trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/MapImage.java

    r12630 r12722  
    3232     * ImageIcon can change while the image is loading.
    3333     */
    34     private BufferedImage img;
     34    private Image img;
    3535
    3636    /**
     
    102102     * @return the image
    103103     */
    104     public BufferedImage getImage(boolean disabled) {
     104    public Image getImage(boolean disabled) {
    105105        if (disabled) {
    106106            return getDisabled();
     
    110110    }
    111111
    112     private BufferedImage getDisabled() {
     112    private Image getDisabled() {
    113113        if (disabledImgCache != null)
    114114                return disabledImgCache;
     
    127127    }
    128128
    129     private BufferedImage getImage() {
     129    private Image getImage() {
    130130        if (img != null)
    131131            return img;
     
    144144                            source.logWarning(tr("Failed to locate image ''{0}''", name));
    145145                            ImageIcon noIcon = MapPaintStyles.getNoIconIcon(source);
    146                             img = noIcon == null ? null : (BufferedImage) noIcon.getImage();
     146                            img = noIcon == null ? null : noIcon.getImage();
    147147                        } else {
    148                             img = (BufferedImage) rescale(result.getImage());
     148                            img = rescale(result.getImage());
    149149                        }
    150150                        if (temporary) {
     
    160160        synchronized (this) {
    161161            if (img == null) {
    162                 img = (BufferedImage) ImageProvider.get("clock").getImage();
     162                img = ImageProvider.get("clock").getImage();
    163163                temporary = true;
    164164            }
  • trunk/src/org/openstreetmap/josm/tools/ImageOverlay.java

    r9078 r12722  
    8181        }
    8282        ImageIcon overlay;
    83         if (width != -1 || height != -1) {
    84             image = new ImageProvider(image).resetMaxSize(new Dimension(width, height));
    85         }
     83        image = new ImageProvider(image).setMaxSize(new Dimension(width, height));
    8684        overlay = image.get();
    8785        int x, y;
  • trunk/src/org/openstreetmap/josm/tools/ImageProvider.java

    r12682 r12722  
    277277    /** <code>true</code> if icon must be grayed out */
    278278    protected boolean isDisabled;
     279    /** <code>true</code> if multi-resolution image is requested */
     280    protected boolean multiResolution = true;
    279281
    280282    private static SVGUniverse svgUniverse;
     
    288290     * Caches the image data for rotated versions of the same image.
    289291     */
    290     private static final Map<Image, Map<Long, ImageResource>> ROTATE_CACHE = new HashMap<>();
     292    private static final Map<Image, Map<Long, Image>> ROTATE_CACHE = new HashMap<>();
    291293
    292294    private static final ExecutorService IMAGE_FETCHER =
     
    334336        this.overlayInfo = image.overlayInfo;
    335337        this.isDisabled = image.isDisabled;
     338        this.multiResolution = image.multiResolution;
    336339    }
    337340
     
    596599
    597600    /**
     601     * Decide, if multi-resolution image is requested (default <code>true</code>).
     602     * <p>
     603     * A <code>java.awt.image.MultiResolutionImage</code> is a Java 9 {@link Image}
     604     * implementation, which adds support for HiDPI displays. The effect will be
     605     * that in HiDPI mode, when GUI elements are scaled by a factor 1.5, 2.0, etc.,
     606     * the images are not just up-scaled, but a higher resolution version of the
     607     * image is rendered instead.
     608     * <p>
     609     * Use {@link HiDPISupport#getBaseImage(java.awt.Image)} to extract the original
     610     * image from a multi-resolution image.
     611     * <p>
     612     * See {@link HiDPISupport#processMRImage} for how to process the image without
     613     * removing the multi-resolution magic.
     614     * @param multiResolution true, if multi-resolution image is requested
     615     * @return the current object, for convenience
     616     */
     617    public ImageProvider setMultiResolution(boolean multiResolution) {
     618        this.multiResolution = multiResolution;
     619        return this;
     620    }
     621
     622    /**
    598623     * Execute the image request and scale result.
    599624     * @return the requested image or null if the request failed
     
    606631        }
    607632        if (virtualMaxWidth != -1 || virtualMaxHeight != -1)
    608             return ir.getImageIconBounded(new Dimension(virtualMaxWidth, virtualMaxHeight));
     633            return ir.getImageIconBounded(new Dimension(virtualMaxWidth, virtualMaxHeight), multiResolution);
    609634        else
    610             return ir.getImageIcon(new Dimension(virtualWidth, virtualHeight));
     635            return ir.getImageIcon(new Dimension(virtualWidth, virtualHeight), multiResolution);
    611636    }
    612637
     
    12761301
    12771302    /**
    1278      * Creates a rotated version of the input image, scaled to the given dimension.
     1303     * Creates a rotated version of the input image.
    12791304     *
    12801305     * @param img the image to be rotated.
     
    12821307     * will mod it with 360 before using it. More over for caching performance, it will be rounded to
    12831308     * an entire value between 0 and 360.
    1284      * @param dimension The requested dimensions. Use (-1,-1) for the original size
    1285      * and (width, -1) to set the width, but otherwise scale the image proportionally.
     1309     * @param dimension ignored
    12861310     * @return the image after rotating and scaling.
    12871311     * @since 6172
     
    12911315
    12921316        // convert rotatedAngle to an integer value from 0 to 360
    1293         Long originalAngle = Math.round(rotatedAngle % 360);
    1294         if (rotatedAngle != 0 && originalAngle == 0) {
    1295             originalAngle = 360L;
    1296         }
    1297 
    1298         ImageResource imageResource;
     1317        Long angleLong = Math.round(rotatedAngle % 360);
     1318        Long originalAngle = rotatedAngle != 0 && angleLong == 0 ? 360L : angleLong;
    12991319
    13001320        synchronized (ROTATE_CACHE) {
    1301             Map<Long, ImageResource> cacheByAngle = ROTATE_CACHE.get(img);
     1321            Map<Long, Image> cacheByAngle = ROTATE_CACHE.get(img);
    13021322            if (cacheByAngle == null) {
    13031323                cacheByAngle = new HashMap<>();
     
    13051325            }
    13061326
    1307             imageResource = cacheByAngle.get(originalAngle);
    1308 
    1309             if (imageResource == null) {
     1327            Image rotatedImg = cacheByAngle.get(originalAngle);
     1328
     1329            if (rotatedImg == null) {
    13101330                // convert originalAngle to a value from 0 to 90
    13111331                double angle = originalAngle % 90;
     
    13131333                    angle = 90.0;
    13141334                }
    1315 
    13161335                double radian = Utils.toRadians(angle);
    13171336
    1318                 new ImageIcon(img); // load completely
    1319                 int iw = img.getWidth(null);
    1320                 int ih = img.getHeight(null);
    1321                 int w;
    1322                 int h;
    1323 
    1324                 if ((originalAngle >= 0 && originalAngle <= 90) || (originalAngle > 180 && originalAngle <= 270)) {
    1325                     w = (int) (iw * Math.sin(DEGREE_90 - radian) + ih * Math.sin(radian));
    1326                     h = (int) (iw * Math.sin(radian) + ih * Math.sin(DEGREE_90 - radian));
    1327                 } else {
    1328                     w = (int) (ih * Math.sin(DEGREE_90 - radian) + iw * Math.sin(radian));
    1329                     h = (int) (ih * Math.sin(radian) + iw * Math.sin(DEGREE_90 - radian));
    1330                 }
    1331                 Image image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
    1332                 imageResource = new ImageResource(image);
    1333                 cacheByAngle.put(originalAngle, imageResource);
    1334                 Graphics g = image.getGraphics();
    1335                 Graphics2D g2d = (Graphics2D) g.create();
    1336 
    1337                 // calculate the center of the icon.
    1338                 int cx = iw / 2;
    1339                 int cy = ih / 2;
    1340 
    1341                 // move the graphics center point to the center of the icon.
    1342                 g2d.translate(w / 2, h / 2);
    1343 
    1344                 // rotate the graphics about the center point of the icon
    1345                 g2d.rotate(Utils.toRadians(originalAngle));
    1346 
    1347                 g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
    1348                 g2d.drawImage(img, -cx, -cy, null);
    1349 
    1350                 g2d.dispose();
    1351                 new ImageIcon(image); // load completely
    1352             }
    1353             return imageResource.getImageIcon(dimension).getImage();
     1337                rotatedImg = HiDPISupport.processMRImage(img, img0 -> {
     1338                    new ImageIcon(img0); // load completely
     1339                    int iw = img0.getWidth(null);
     1340                    int ih = img0.getHeight(null);
     1341                    int w;
     1342                    int h;
     1343
     1344                    if ((originalAngle >= 0 && originalAngle <= 90) || (originalAngle > 180 && originalAngle <= 270)) {
     1345                        w = (int) (iw * Math.sin(DEGREE_90 - radian) + ih * Math.sin(radian));
     1346                        h = (int) (iw * Math.sin(radian) + ih * Math.sin(DEGREE_90 - radian));
     1347                    } else {
     1348                        w = (int) (ih * Math.sin(DEGREE_90 - radian) + iw * Math.sin(radian));
     1349                        h = (int) (ih * Math.sin(radian) + iw * Math.sin(DEGREE_90 - radian));
     1350                    }
     1351                    Image image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
     1352                    Graphics g = image.getGraphics();
     1353                    Graphics2D g2d = (Graphics2D) g.create();
     1354
     1355                    // calculate the center of the icon.
     1356                    int cx = iw / 2;
     1357                    int cy = ih / 2;
     1358
     1359                    // move the graphics center point to the center of the icon.
     1360                    g2d.translate(w / 2, h / 2);
     1361
     1362                    // rotate the graphics about the center point of the icon
     1363                    g2d.rotate(Utils.toRadians(originalAngle));
     1364
     1365                    g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
     1366                    g2d.drawImage(img0, -cx, -cy, null);
     1367
     1368                    g2d.dispose();
     1369                    new ImageIcon(image); // load completely
     1370                    return image;
     1371                });
     1372                cacheByAngle.put(originalAngle, rotatedImg);
     1373            }
     1374            return rotatedImg;
    13541375        }
    13551376    }
     
    14121433                        double scaleFactor = Math.min(backgroundRealWidth / (double) iconRealWidth, backgroundRealHeight
    14131434                                / (double) iconRealHeight);
    1414                         BufferedImage iconImage = icon.getImage(false);
     1435                        Image iconImage = icon.getImage(false);
    14151436                        Image scaledIcon;
    14161437                        final int scaledWidth;
  • trunk/src/org/openstreetmap/josm/tools/ImageResource.java

    r12682 r12722  
    3131     * Caches the image data for resized versions of the same image.
    3232     */
    33     private final Map<Dimension, Image> imgCache = new HashMap<>();
     33    private final Map<Dimension, BufferedImage> imgCache = new HashMap<>();
    3434    /**
    3535     * SVG diagram information in case of SVG vector image.
     
    151151
    152152    /**
    153      * Get an ImageIcon object for the image of this resource
     153     * Get an ImageIcon object for the image of this resource.
     154     * <p>
     155     * Will return a multi-resolution image by default (if possible).
    154156     * @param  dim The requested dimensions. Use (-1,-1) for the original size and (width, -1)
    155157     *         to set the width, but otherwise scale the image proportionally.
     158     * @see #getImageIconBounded(java.awt.Dimension, boolean)
    156159     * @return ImageIcon object for the image of this resource, scaled according to dim
    157160     */
    158161    public ImageIcon getImageIcon(Dimension dim) {
     162        return getImageIcon(dim, true);
     163    }
     164   
     165    /**
     166     * Get an ImageIcon object for the image of this resource.
     167     * @param  dim The requested dimensions. Use (-1,-1) for the original size and (width, -1)
     168     *         to set the width, but otherwise scale the image proportionally.
     169     * @param  multiResolution If true, return a multi-resolution image
     170     * (java.awt.image.MultiResolutionImage in Java 9), otherwise a plain {@link BufferedImage}.
     171     * When running Java 8, this flag has no effect and a plain image will be returned in any case.
     172     * @return ImageIcon object for the image of this resource, scaled according to dim
     173     * @since 12722
     174     */
     175    public ImageIcon getImageIcon(Dimension dim, boolean multiResolution) {
    159176        if (dim.width < -1 || dim.width == 0 || dim.height < -1 || dim.height == 0)
    160177            throw new IllegalArgumentException(dim+" is invalid");
    161         Image img = imgCache.get(dim);
    162         if (img != null) {
     178        BufferedImage img = imgCache.get(dim);
     179        if (img == null) {
     180            if (svg != null) {
     181                Dimension realDim = GuiSizesHelper.getDimensionDpiAdjusted(dim);
     182                img = ImageProvider.createImageFromSvg(svg, realDim);
     183                if (img == null) {
     184                    return null;
     185                }
     186            } else {
     187                if (baseImage == null) throw new AssertionError();
     188
     189                int realWidth = GuiSizesHelper.getSizeDpiAdjusted(dim.width);
     190                int realHeight = GuiSizesHelper.getSizeDpiAdjusted(dim.height);
     191                ImageIcon icon = new ImageIcon(baseImage);
     192                if (realWidth == -1 && realHeight == -1) {
     193                    realWidth = GuiSizesHelper.getSizeDpiAdjusted(icon.getIconWidth());
     194                    realHeight = GuiSizesHelper.getSizeDpiAdjusted(icon.getIconHeight());
     195                } else if (realWidth == -1) {
     196                    realWidth = Math.max(1, icon.getIconWidth() * realHeight / icon.getIconHeight());
     197                } else if (realHeight == -1) {
     198                    realHeight = Math.max(1, icon.getIconHeight() * realWidth / icon.getIconWidth());
     199                }
     200                Image i = icon.getImage().getScaledInstance(realWidth, realHeight, Image.SCALE_SMOOTH);
     201                img = new BufferedImage(realWidth, realHeight, BufferedImage.TYPE_INT_ARGB);
     202                img.getGraphics().drawImage(i, 0, 0, null);
     203            }
     204            if (overlayInfo != null) {
     205                for (ImageOverlay o : overlayInfo) {
     206                    o.process(img);
     207                }
     208            }
     209            if (isDisabled) {
     210                //Use default Swing functionality to make icon look disabled by applying grayscaling filter.
     211                Icon disabledIcon = UIManager.getLookAndFeel().getDisabledIcon(null, new ImageIcon(img));
     212                if (disabledIcon == null) {
     213                    return null;
     214                }
     215
     216                //Convert Icon to ImageIcon with BufferedImage inside
     217                img = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
     218                disabledIcon.paintIcon(new JPanel(), img.getGraphics(), 0, 0);
     219            }
     220            imgCache.put(dim, img);
     221        }
     222
     223        if (!multiResolution)
    163224            return new ImageIcon(img);
    164         }
    165         BufferedImage bimg;
    166         if (svg != null) {
    167             Dimension realDim = GuiSizesHelper.getDimensionDpiAdjusted(dim);
    168             bimg = ImageProvider.createImageFromSvg(svg, realDim);
    169             if (bimg == null) {
    170                 return null;
    171             }
    172         } else {
    173             if (baseImage == null) throw new AssertionError();
    174 
    175             int realWidth = GuiSizesHelper.getSizeDpiAdjusted(dim.width);
    176             int realHeight = GuiSizesHelper.getSizeDpiAdjusted(dim.height);
    177             ImageIcon icon = new ImageIcon(baseImage);
    178             if (realWidth == -1 && realHeight == -1) {
    179                 realWidth = GuiSizesHelper.getSizeDpiAdjusted(icon.getIconWidth());
    180                 realHeight = GuiSizesHelper.getSizeDpiAdjusted(icon.getIconHeight());
    181             } else if (realWidth == -1) {
    182                 realWidth = Math.max(1, icon.getIconWidth() * realHeight / icon.getIconHeight());
    183             } else if (realHeight == -1) {
    184                 realHeight = Math.max(1, icon.getIconHeight() * realWidth / icon.getIconWidth());
    185             }
    186             Image i = icon.getImage().getScaledInstance(realWidth, realHeight, Image.SCALE_SMOOTH);
    187             bimg = new BufferedImage(realWidth, realHeight, BufferedImage.TYPE_INT_ARGB);
    188             bimg.getGraphics().drawImage(i, 0, 0, null);
    189         }
    190         if (overlayInfo != null) {
    191             for (ImageOverlay o : overlayInfo) {
    192                 o.process(bimg);
    193             }
    194         }
    195         if (isDisabled) {
    196             //Use default Swing functionality to make icon look disabled by applying grayscaling filter.
    197             Icon disabledIcon = UIManager.getLookAndFeel().getDisabledIcon(null, new ImageIcon(bimg));
    198             if (disabledIcon == null) {
    199                 return null;
    200             }
    201 
    202             //Convert Icon to ImageIcon with BufferedImage inside
    203             bimg = new BufferedImage(bimg.getWidth(), bimg.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
    204             disabledIcon.paintIcon(new JPanel(), bimg.getGraphics(), 0, 0);
    205         }
    206         imgCache.put(dim, bimg);
    207         return new ImageIcon(bimg);
     225        else {
     226            try {
     227                Image mrImg = HiDPISupport.getMultiResolutionImage(img, this);
     228                return new ImageIcon(mrImg);
     229            } catch (NoClassDefFoundError e) {
     230                return new ImageIcon(img);
     231            }
     232        }
    208233    }
    209234
     
    211236     * Get image icon with a certain maximum size. The image is scaled down
    212237     * to fit maximum dimensions. (Keeps aspect ratio)
     238     * <p>
     239     * Will return a multi-resolution image by default (if possible).
    213240     *
    214241     * @param maxSize The maximum size. One of the dimensions (width or height) can be -1,
    215242     * which means it is not bounded.
    216243     * @return ImageIcon object for the image of this resource, scaled down if needed, according to maxSize
     244     * @see #getImageIconBounded(java.awt.Dimension, boolean)
    217245     */
    218246    public ImageIcon getImageIconBounded(Dimension maxSize) {
     247        return getImageIconBounded(maxSize, true);
     248    }
     249
     250    /**
     251     * Get image icon with a certain maximum size. The image is scaled down
     252     * to fit maximum dimensions. (Keeps aspect ratio)
     253     *
     254     * @param maxSize The maximum size. One of the dimensions (width or height) can be -1,
     255     * which means it is not bounded.
     256     * @param  multiResolution If true, return a multi-resolution image
     257     * (java.awt.image.MultiResolutionImage in Java 9), otherwise a plain {@link BufferedImage}.
     258     * When running Java 8, this flag has no effect and a plain image will be returned in any case.
     259     * @return ImageIcon object for the image of this resource, scaled down if needed, according to maxSize
     260     * @since 12722
     261     */
     262    public ImageIcon getImageIconBounded(Dimension maxSize, boolean multiResolution) {
    219263        if (maxSize.width < -1 || maxSize.width == 0 || maxSize.height < -1 || maxSize.height == 0)
    220264            throw new IllegalArgumentException(maxSize+" is invalid");
     
    240284
    241285        if (maxWidth == -1 && maxHeight == -1)
    242             return getImageIcon(DEFAULT_DIMENSION);
     286            return getImageIcon(DEFAULT_DIMENSION, multiResolution);
    243287        else if (maxWidth == -1)
    244             return getImageIcon(new Dimension(-1, maxHeight));
     288            return getImageIcon(new Dimension(-1, maxHeight), multiResolution);
    245289        else if (maxHeight == -1)
    246             return getImageIcon(new Dimension(maxWidth, -1));
     290            return getImageIcon(new Dimension(maxWidth, -1), multiResolution);
    247291        else if (sourceWidth / maxWidth > sourceHeight / maxHeight)
    248             return getImageIcon(new Dimension(maxWidth, -1));
     292            return getImageIcon(new Dimension(maxWidth, -1), multiResolution);
    249293        else
    250             return getImageIcon(new Dimension(-1, maxHeight));
     294            return getImageIcon(new Dimension(-1, maxHeight), multiResolution);
    251295   }
    252296}
Note: See TracChangeset for help on using the changeset viewer.