Ignore:
Timestamp:
2017-09-04T18:52:06+02:00 (4 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/gui
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • 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            }
Note: See TracChangeset for help on using the changeset viewer.