This is an automated email from the ASF dual-hosted git repository. ebakke pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/netbeans.git
commit 894376f42517da2dd028852fcb3bb0d1e4b10609 Author: Eirik Bakke <[email protected]> AuthorDate: Thu May 30 13:52:57 2019 -0400 Improve rendering quality of scaled bitmap icons on HiDPI displays. Having centralized icon painting into ImageUtilities.ToolTipImage.paintIcon in the previous commits, we can now add a few painting tweaks to improve the appearance of low-resolution bitmap icons that must be scaled up for HiDPI displays. See the before/after screenshots that are attached to JIRA ticket NETBEANS-2614. --- .../src/org/openide/util/ImageUtilities.java | 50 +++++++++++++++++++--- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/platform/openide.util.ui/src/org/openide/util/ImageUtilities.java b/platform/openide.util.ui/src/org/openide/util/ImageUtilities.java index 8783424..e39a306 100644 --- a/platform/openide.util.ui/src/org/openide/util/ImageUtilities.java +++ b/platform/openide.util.ui/src/org/openide/util/ImageUtilities.java @@ -21,11 +21,14 @@ package org.openide.util; import java.awt.Component; import java.awt.Graphics; +import java.awt.Graphics2D; import java.awt.HeadlessException; import java.awt.Image; import java.awt.MediaTracker; +import java.awt.RenderingHints; import java.awt.Toolkit; import java.awt.Transparency; +import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.ImageObserver; @@ -160,7 +163,8 @@ public final class ImageUtilities { return loadImageInternal(resource, localized); } - // Private version with more specific return type. + /* Private version of the method showing the more specific return type. We always return a + ToolTipImage, to take advantage of its rendering tweaks for HiDPI screens. */ private static ToolTipImage loadImageInternal(String resource, boolean localized) { // Avoid a NPE that could previously occur in the isDarkLaF case only. See NETBEANS-2401. if (resource == null) { @@ -177,9 +181,6 @@ public final class ImageUtilities { // only non _dark images need filtering RGBImageFilter imageFilter = getImageIconFilter(); if (null != image && null != imageFilter) { - /* Make sure that every Image loaded by this class is a ToolTipImage, whether or not - a filter is applied. That way we're less likely to introduce bugs that only occur on - certain LAFs. */ image = icon2ToolTipImage(FilteredIcon.create(imageFilter, image)); } } @@ -276,6 +277,8 @@ public final class ImageUtilities { * @return icon corresponding icon */ public static final Icon image2Icon(Image image) { + /* Make sure to always return a ToolTipImage, to take advantage of its rendering tweaks for + HiDPI screens. */ return (image instanceof ToolTipImage) ? (ToolTipImage) image : assignToolTipToImageInternal(image, ""); } @@ -954,7 +957,44 @@ public final class ImageUtilities { if (delegateIcon != null) { delegateIcon.paintIcon(c, g, x, y); } else { - g.drawImage(this, x, y, null); + /* There is no scalable delegate icon available. On HiDPI displays, this means that + original low-resolution icons will need to be scaled up to a higher resolution. Do a + few tricks here to improve the quality of the scaling. See NETBEANS-2614 and the + before/after screenshots that are attached to said JIRA ticket. */ + Graphics2D g2 = (Graphics2D) g.create(); + try { + final AffineTransform tx = g2.getTransform(); + final int txType = tx.getType(); + final double scale; + if (txType == AffineTransform.TYPE_UNIFORM_SCALE || + txType == (AffineTransform.TYPE_UNIFORM_SCALE | AffineTransform.TYPE_TRANSLATION)) + { + scale = tx.getScaleX(); + } else { + scale = 1.0; + } + if (scale != 1.0) { + /* The default interpolation mode is nearest neighbor. Use bicubic + interpolation instead, which looks better, especially with non-integral + HiDPI scaling factors (e.g. 150%). Even for an integral 2x scaling factor + (used by all Retina displays on MacOS), the blurred appearance of bicubic + scaling ends up looking better on HiDPI displays than the blocky appearance + of nearest neighbor. */ + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); + g2.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); + g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + /* For non-integral scaling factors, we frequently encounter non-integral + device pixel positions. For instance, with a 150% scaling factor, the + logical pixel position (7,0) would map to device pixel position (10.5,0). + On such scaling factors, icons look a lot better if we round the (x,y) + translation to an integral number of device pixels before painting. */ + g2.setTransform(new AffineTransform(scale, 0, 0, scale, + (int) tx.getTranslateX(), (int) tx.getTranslateY())); + } + g2.drawImage(this, x, y, null); + } finally { + g2.dispose(); + } } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected] For further information about the NetBeans mailing lists, visit: https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists
