Ticket #9995: hidpi-support.patch
File hidpi-support.patch, 33.1 KB (added by , 8 years ago) |
---|
-
src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java
81 81 import org.openstreetmap.josm.tools.ImageProvider; 82 82 import org.openstreetmap.josm.tools.JosmRuntimeException; 83 83 import org.openstreetmap.josm.tools.Logging; 84 import org.openstreetmap.josm.tools.HiDPISupport; 84 85 import org.openstreetmap.josm.tools.Utils; 85 86 import org.openstreetmap.josm.tools.bugreport.BugReport; 86 87 … … 416 417 g.setClip(oldClip); 417 418 } 418 419 } 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, 420 425 new Rectangle(0, 0, fillImage.getWidth(), fillImage.getHeight())); 421 426 g.setPaint(texture); 422 427 Float alpha = fillImage.getAlphaFloat(); … … 656 661 657 662 double startOffset = computeStartOffset(phase, repeat); 658 663 659 BufferedImage image = pattern.getImage(disabled);664 Image image = pattern.getImage(disabled); 660 665 661 666 path.visitClippedLine(repeat, (inLineOffset, start, end, startIsOldEnd) -> { 662 667 final double segmentLength = start.distanceToInView(end); … … 1149 1154 } 1150 1155 displayText(() -> { 1151 1156 AffineTransform defaultTransform = g.getTransform(); 1152 g. setTransform(at);1157 g.transform(at); 1153 1158 g.setFont(text.font); 1154 1159 g.drawString(name, 0, 0); 1155 1160 g.setTransform(defaultTransform); -
src/org/openstreetmap/josm/gui/MapView.java
8 8 import java.awt.Graphics2D; 9 9 import java.awt.Point; 10 10 import java.awt.Rectangle; 11 import java.awt.Shape; 11 12 import java.awt.event.ComponentAdapter; 12 13 import java.awt.event.ComponentEvent; 13 14 import java.awt.event.KeyEvent; … … 14 15 import java.awt.event.MouseAdapter; 15 16 import java.awt.event.MouseEvent; 16 17 import java.awt.event.MouseMotionListener; 18 import java.awt.geom.AffineTransform; 17 19 import java.awt.geom.Area; 18 20 import java.awt.image.BufferedImage; 19 21 import java.beans.PropertyChangeEvent; … … 510 512 } 511 513 512 514 private void drawMapContent(Graphics g) { 515 Graphics2D gg = (Graphics2D) g; 516 AffineTransform trOrig = gg.getTransform(); 517 double uiScaleX = gg.getTransform().getScaleX(); 518 double uiScaleY = gg.getTransform().getScaleY(); 519 int width = (int) Math.round(getWidth() * uiScaleX); 520 int height = (int) Math.round(getHeight() * uiScaleY); 521 522 AffineTransform trDef = AffineTransform.getScaleInstance(uiScaleX, uiScaleY); 523 Shape scaledClip = trDef.createTransformedShape(g.getClip()); 524 513 525 List<Layer> visibleLayers = layerManager.getVisibleLayersInZOrder(); 514 526 515 527 int nonChangedLayersCount = 0; … … 528 540 && lastClipBounds.contains(g.getClipBounds()) 529 541 && nonChangedLayers.equals(visibleLayers.subList(0, nonChangedLayers.size())); 530 542 531 if (null == offscreenBuffer || offscreenBuffer.getWidth() != getWidth() || offscreenBuffer.getHeight() != getHeight()) {532 offscreenBuffer = new BufferedImage( getWidth(), getHeight(), BufferedImage.TYPE_3BYTE_BGR);543 if (null == offscreenBuffer || offscreenBuffer.getWidth() != width || offscreenBuffer.getHeight() != height) { 544 offscreenBuffer = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR); 533 545 } 534 546 535 Graphics2D tempG = offscreenBuffer.createGraphics();536 tempG.setClip(g.getClip());537 538 547 if (!canUseBuffer || nonChangedLayersBuffer == null) { 539 548 if (null == nonChangedLayersBuffer 540 || nonChangedLayersBuffer.getWidth() != getWidth() || nonChangedLayersBuffer.getHeight() != getHeight()) {541 nonChangedLayersBuffer = new BufferedImage( getWidth(), getHeight(), BufferedImage.TYPE_3BYTE_BGR);549 || nonChangedLayersBuffer.getWidth() != width || nonChangedLayersBuffer.getHeight() != height) { 550 nonChangedLayersBuffer = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR); 542 551 } 543 552 Graphics2D g2 = nonChangedLayersBuffer.createGraphics(); 544 g2.setClip(g.getClip()); 553 g2.setClip(scaledClip); 554 g2.setTransform(trDef); 545 555 g2.setColor(PaintColors.getBackgroundColor()); 546 g2.fillRect(0, 0, getWidth(), getHeight());556 g2.fillRect(0, 0, width, height); 547 557 548 558 for (int i = 0; i < nonChangedLayersCount; i++) { 549 559 paintLayer(visibleLayers.get(i), g2); … … 552 562 // Maybe there were more unchanged layers then last time - draw them to buffer 553 563 if (nonChangedLayers.size() != nonChangedLayersCount) { 554 564 Graphics2D g2 = nonChangedLayersBuffer.createGraphics(); 555 g2.setClip(g.getClip()); 565 g2.setClip(scaledClip); 566 g2.setTransform(trDef); 556 567 for (int i = nonChangedLayers.size(); i < nonChangedLayersCount; i++) { 557 568 paintLayer(visibleLayers.get(i), g2); 558 569 } … … 564 575 lastViewID = getViewID(); 565 576 lastClipBounds = g.getClipBounds(); 566 577 578 Graphics2D tempG = offscreenBuffer.createGraphics(); 579 tempG.setClip(scaledClip); 580 tempG.setTransform(new AffineTransform()); 567 581 tempG.drawImage(nonChangedLayersBuffer, 0, 0, null); 568 582 tempG.setTransform(trDef); 583 569 584 for (int i = nonChangedLayersCount; i < visibleLayers.size(); i++) { 570 585 paintLayer(visibleLayers.get(i), tempG); 571 586 } 572 587 573 588 try { 574 drawTemporaryLayers(tempG, getLatLonBounds(g.getClipBounds())); 589 drawTemporaryLayers(tempG, getLatLonBounds(new Rectangle( 590 (int) Math.round(g.getClipBounds().x * uiScaleX), 591 (int) Math.round(g.getClipBounds().y * uiScaleY)))); 575 592 } catch (JosmRuntimeException | IllegalArgumentException | IllegalStateException e) { 576 593 BugReport.intercept(e).put("temporaryLayers", temporaryLayers).warn(); 577 594 } … … 596 613 } 597 614 598 615 try { 599 g.drawImage(offscreenBuffer, 0, 0, null); 616 gg.setTransform(new AffineTransform(1, 0, 0, 1, trOrig.getTranslateX(), trOrig.getTranslateY())); 617 gg.drawImage(offscreenBuffer, 0, 0, null); 600 618 } catch (ClassCastException e) { 601 619 // See #11002 and duplicate tickets. On Linux with Java >= 8 Many users face this error here: 602 620 // … … 622 640 // 623 641 // But the application seems to work fine after, so let's just log the error 624 642 Logging.error(e); 643 } finally { 644 gg.setTransform(trOrig); 625 645 } 626 646 } 627 647 -
src/org/openstreetmap/josm/gui/mappaint/styleelement/AreaElement.java
2 2 package org.openstreetmap.josm.gui.mappaint.styleelement; 3 3 4 4 import java.awt.Color; 5 import java.awt.Image; 6 import java.awt.image.BufferedImage; 5 7 import java.util.Objects; 6 8 7 9 import org.openstreetmap.josm.Main; … … 15 17 import org.openstreetmap.josm.gui.mappaint.Environment; 16 18 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.IconReference; 17 19 import org.openstreetmap.josm.tools.CheckParameterUtil; 20 import org.openstreetmap.josm.tools.HiDPISupport; 18 21 import org.openstreetmap.josm.tools.Utils; 19 22 20 23 /** … … 78 81 IconReference iconRef = c.get(FILL_IMAGE, null, IconReference.class); 79 82 if (iconRef != null) { 80 83 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( 83 89 fillImage.getWidth() / 2, fillImage.getHeight() / 2) 84 90 ); 85 91 -
src/org/openstreetmap/josm/gui/mappaint/styleelement/MapImage.java
31 31 /** 32 32 * ImageIcon can change while the image is loading. 33 33 */ 34 private BufferedImage img;34 private Image img; 35 35 36 36 /** 37 37 * The alpha (opacity) value of the image. It is multiplied to the image alpha channel. … … 101 101 * @param disabled {@code} true to request disabled version, {@code false} for the standard version 102 102 * @return the image 103 103 */ 104 public BufferedImage getImage(boolean disabled) {104 public Image getImage(boolean disabled) { 105 105 if (disabled) { 106 106 return getDisabled(); 107 107 } else { … … 109 109 } 110 110 } 111 111 112 private BufferedImage getDisabled() {112 private Image getDisabled() { 113 113 if (disabledImgCache != null) 114 114 return disabledImgCache; 115 115 if (img == null) … … 126 126 return disabledImgCache; 127 127 } 128 128 129 private BufferedImage getImage() {129 private Image getImage() { 130 130 if (img != null) 131 131 return img; 132 132 temporary = false; … … 143 143 if (result == null) { 144 144 source.logWarning(tr("Failed to locate image ''{0}''", name)); 145 145 ImageIcon noIcon = MapPaintStyles.getNoIconIcon(source); 146 img = noIcon == null ? null : (BufferedImage)noIcon.getImage();146 img = noIcon == null ? null : noIcon.getImage(); 147 147 } else { 148 img = (BufferedImage)rescale(result.getImage());148 img = rescale(result.getImage()); 149 149 } 150 150 if (temporary) { 151 151 disabledImgCache = null; … … 159 159 ); 160 160 synchronized (this) { 161 161 if (img == null) { 162 img = (BufferedImage)ImageProvider.get("clock").getImage();162 img = ImageProvider.get("clock").getImage(); 163 163 temporary = true; 164 164 } 165 165 } -
src/org/openstreetmap/josm/gui/util/GuiHelper.java
11 11 import java.awt.DisplayMode; 12 12 import java.awt.Font; 13 13 import java.awt.Frame; 14 import java.awt.GraphicsConfiguration; 14 15 import java.awt.GraphicsDevice; 15 16 import java.awt.GraphicsEnvironment; 16 17 import java.awt.GridBagLayout; … … 23 24 import java.awt.event.KeyEvent; 24 25 import java.awt.event.MouseAdapter; 25 26 import java.awt.event.MouseEvent; 27 import java.awt.geom.AffineTransform; 26 28 import java.awt.image.FilteredImageSource; 27 29 import java.lang.reflect.InvocationTargetException; 28 30 import java.util.Arrays; … … 65 67 import org.openstreetmap.josm.tools.ImageProvider.ImageSizes; 66 68 import org.openstreetmap.josm.tools.LanguageInfo; 67 69 import org.openstreetmap.josm.tools.Logging; 70 import org.openstreetmap.josm.tools.Utils; 68 71 import org.openstreetmap.josm.tools.bugreport.BugReport; 69 72 import org.openstreetmap.josm.tools.bugreport.ReportedException; 70 73 -
src/org/openstreetmap/josm/tools/HiDPISupport.java
1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.tools; 3 4 import java.awt.Dimension; 5 import java.awt.GraphicsConfiguration; 6 import java.awt.GraphicsEnvironment; 7 import java.awt.Image; 8 import java.awt.geom.AffineTransform; 9 import java.lang.reflect.Constructor; 10 import java.lang.reflect.InvocationTargetException; 11 import java.lang.reflect.Method; 12 import java.util.Arrays; 13 import java.util.Collections; 14 import java.util.List; 15 import java.util.Optional; 16 import java.util.function.Function; 17 import java.util.stream.Collectors; 18 import java.util.stream.IntStream; 19 20 import javax.swing.ImageIcon; 21 22 /** 23 * Helper class for HiDPI support. 24 * 25 * Gives access to the class <code>BaseMultiResolutionImage</code> via reflection, 26 * in case it is on classpath. This is to be expected for Java 9, but not for Java 8 27 * runtime. 28 * 29 * @since xxx 30 */ 31 public class HiDPISupport { 32 33 private static volatile Optional<Class<? extends Image>> baseMultiResolutionImageClass; 34 private static volatile Optional<Constructor<? extends Image>> baseMultiResolutionImageConstructor; 35 private static volatile Optional<Method> resolutionVariantsMethod; 36 37 public static Image getMultiResolutionImage(Image base, ImageResource ir) { 38 double uiScale = getHiDPIScale(); 39 if (uiScale != 1.0 && getBaseMultiResolutionImageConstructor().isPresent()) { 40 ImageIcon zoomed = ir.getImageIconBasic(new Dimension( 41 (int) Math.round(base.getWidth(null) * uiScale), 42 (int) Math.round(base.getHeight(null) * uiScale))); 43 Image mrImg = getMultiResolutionImage(Arrays.asList(base, zoomed.getImage())); 44 if (mrImg != null) return mrImg; 45 } 46 return base; 47 } 48 49 public static Image getMultiResolutionImage(List<Image> imgs) { 50 if (getBaseMultiResolutionImageConstructor().isPresent()) { 51 Constructor<? extends Image> c = getBaseMultiResolutionImageConstructor().get(); 52 try { 53 return c.newInstance((Object) imgs.toArray(new Image[0])); 54 } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) { 55 Logging.error("Unexpected error while instantiating object of class BaseMultiResolutionImage: " + ex); 56 } 57 } 58 return imgs.get(0); 59 } 60 61 public static Image getBaseImage(Image img) { 62 if (!getBaseMultiResolutionImageClass().isPresent() || !getResolutionVariantsMethod().isPresent()) { 63 return img; 64 } 65 if (getBaseMultiResolutionImageClass().get().isInstance(img)) { 66 try { 67 @SuppressWarnings("unchecked") 68 List<Image> imgVars = (List) getResolutionVariantsMethod().get().invoke(img); 69 if (!imgVars.isEmpty()) { 70 return imgVars.get(0); 71 } 72 } catch (IllegalAccessException | InvocationTargetException ex) { 73 Logging.error("Unexpected error while calling method: " + ex); 74 } 75 } 76 return img; 77 } 78 79 public static List<Image> getResolutionVariants(Image img) { 80 if (!getBaseMultiResolutionImageClass().isPresent() || !getResolutionVariantsMethod().isPresent()) { 81 return Collections.singletonList(img); 82 } 83 if (getBaseMultiResolutionImageClass().get().isInstance(img)) { 84 try { 85 @SuppressWarnings("unchecked") 86 List<Image> imgVars = (List) getResolutionVariantsMethod().get().invoke(img); 87 if (!imgVars.isEmpty()) { 88 return imgVars; 89 } 90 } catch (IllegalAccessException | InvocationTargetException ex) { 91 Logging.error("Unexpected error while calling method: " + ex); 92 } 93 } 94 return Collections.singletonList(img); 95 } 96 97 private static double getHiDPIScale() { 98 GraphicsConfiguration gc = GraphicsEnvironment 99 .getLocalGraphicsEnvironment() 100 .getDefaultScreenDevice(). 101 getDefaultConfiguration(); 102 AffineTransform transform = gc.getDefaultTransform(); 103 if (!Utils.equalsEpsilon(transform.getScaleX(), transform.getScaleY())) { 104 Logging.warn("Unexpected ui transform: " + transform); 105 } 106 return transform.getScaleX(); 107 } 108 109 private static Optional<Class<? extends Image>> getBaseMultiResolutionImageClass() { 110 if (baseMultiResolutionImageClass == null) { 111 synchronized (HiDPISupport.class) { 112 if (baseMultiResolutionImageClass == null) { 113 try { 114 @SuppressWarnings("unchecked") 115 Class<? extends Image> c = (Class) Class.forName("java.awt.image.BaseMultiResolutionImage"); 116 baseMultiResolutionImageClass = Optional.ofNullable(c); 117 } catch (ClassNotFoundException ex) { 118 // class is not present in Java 8 119 baseMultiResolutionImageClass = Optional.empty(); 120 } 121 } 122 } 123 } 124 return baseMultiResolutionImageClass; 125 } 126 127 128 private static Optional<Constructor<? extends Image>> getBaseMultiResolutionImageConstructor() { 129 if (baseMultiResolutionImageConstructor == null) { 130 synchronized (HiDPISupport.class) { 131 if (baseMultiResolutionImageConstructor == null) { 132 getBaseMultiResolutionImageClass().ifPresent(klass -> { 133 try { 134 Constructor<? extends Image> constr = klass.getConstructor(Image[].class); 135 baseMultiResolutionImageConstructor = Optional.ofNullable(constr); 136 } catch (NoSuchMethodException ex) { 137 Logging.error("Cannot find expected constructor: " + ex); 138 } 139 }); 140 if (baseMultiResolutionImageConstructor == null) { 141 baseMultiResolutionImageConstructor = Optional.empty(); 142 } 143 } 144 } 145 } 146 return baseMultiResolutionImageConstructor; 147 } 148 149 private static Optional<Method> getResolutionVariantsMethod() { 150 if (resolutionVariantsMethod == null) { 151 synchronized (HiDPISupport.class) { 152 if (resolutionVariantsMethod == null) { 153 getBaseMultiResolutionImageClass().ifPresent(klass -> { 154 try { 155 Method m = klass.getMethod("getResolutionVariants"); 156 resolutionVariantsMethod = Optional.ofNullable(m); 157 } catch (NoSuchMethodException ex) { 158 Logging.error("Cannot find expected method: "+ex); 159 } 160 }); 161 if (resolutionVariantsMethod == null) { 162 resolutionVariantsMethod = Optional.empty(); 163 } 164 } 165 } 166 } 167 return resolutionVariantsMethod; 168 } 169 170 public static Image processMRImage(Image img, Function<Image, Image> processor) { 171 return processMRImages(Collections.singletonList(img), imgs -> processor.apply(imgs.get(0))); 172 } 173 174 /** 175 * Perform an operation on multi-resolution images. 176 * 177 * When input images are not multi-resolution, it will simply apply the processor once. 178 * Otherwise, the processor will be called for each resolution variant and the 179 * resulting images assembled to become the output multi-resolution image. 180 * @param imgs input images, possibly multi-resolution 181 * @param processor processor taking a list of plain images as input and returning 182 * a single plain image as output 183 * @return multi-resolution image assembled from the output of calls to <code>processor</code> 184 * for each resolution variant 185 */ 186 public static Image processMRImages(List<Image> imgs, Function<List<Image>, Image> processor) { 187 CheckParameterUtil.ensureThat(imgs.size() >= 1, "at least on element expected"); 188 if (!getBaseMultiResolutionImageClass().isPresent()) { 189 return processor.apply(imgs); 190 } 191 List<List<Image>> allVars = imgs.stream().map(HiDPISupport::getResolutionVariants).collect(Collectors.toList()); 192 int maxVariants = allVars.stream().mapToInt(lst -> lst.size()).max().getAsInt(); 193 if (maxVariants == 1) 194 return processor.apply(imgs); 195 List<Image> imgsProcessed = IntStream.range(0, maxVariants) 196 .mapToObj( 197 k -> processor.apply( 198 allVars.stream().map(vars -> vars.get(k)).collect(Collectors.toList()) 199 ) 200 ).collect(Collectors.toList()); 201 return getMultiResolutionImage(imgsProcessed); 202 } 203 204 205 } -
src/org/openstreetmap/josm/tools/ImageOverlay.java
80 80 height = (int) (h*(offsetBottom-offsetTop)); 81 81 } 82 82 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)); 86 84 overlay = image.get(); 87 85 int x, y; 88 86 if (width == -1 && offsetLeft < 0) { -
src/org/openstreetmap/josm/tools/ImageProvider.java
277 277 /** <code>true</code> if icon must be grayed out */ 278 278 protected boolean isDisabled; 279 279 280 protected boolean multiResolution = true; 281 280 282 private static SVGUniverse svgUniverse; 281 283 282 284 /** … … 287 289 /** 288 290 * Caches the image data for rotated versions of the same image. 289 291 */ 290 private static final Map<Image, Map<Long, Image Resource>> ROTATE_CACHE = new HashMap<>();292 private static final Map<Image, Map<Long, Image>> ROTATE_CACHE = new HashMap<>(); 291 293 292 294 private static final ExecutorService IMAGE_FETCHER = 293 295 Executors.newSingleThreadExecutor(Utils.newThreadFactory("image-fetcher-%d", Thread.NORM_PRIORITY)); … … 333 335 this.additionalClassLoaders = image.additionalClassLoaders; 334 336 this.overlayInfo = image.overlayInfo; 335 337 this.isDisabled = image.isDisabled; 338 this.multiResolution = image.multiResolution; 336 339 } 337 340 338 341 /** … … 594 597 return this; 595 598 } 596 599 600 public ImageProvider setMultiResolution(boolean multiResolution) { 601 this.multiResolution = multiResolution; 602 return this; 603 } 604 597 605 /** 598 606 * Execute the image request and scale result. 599 607 * @return the requested image or null if the request failed … … 605 613 return null; 606 614 } 607 615 if (virtualMaxWidth != -1 || virtualMaxHeight != -1) 608 return ir.getImageIconBounded(new Dimension(virtualMaxWidth, virtualMaxHeight) );616 return ir.getImageIconBounded(new Dimension(virtualMaxWidth, virtualMaxHeight), multiResolution); 609 617 else 610 return ir.getImageIcon(new Dimension(virtualWidth, virtualHeight) );618 return ir.getImageIcon(new Dimension(virtualWidth, virtualHeight), multiResolution); 611 619 } 612 620 613 621 /** … … 1275 1283 } 1276 1284 1277 1285 /** 1278 * Creates a rotated version of the input image , scaled to the given dimension.1286 * Creates a rotated version of the input image. 1279 1287 * 1280 1288 * @param img the image to be rotated. 1281 1289 * @param rotatedAngle the rotated angle, in degree, clockwise. It could be any double but we 1282 1290 * will mod it with 360 before using it. More over for caching performance, it will be rounded to 1283 1291 * 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. 1292 * @param dimension ignored 1286 1293 * @return the image after rotating and scaling. 1287 1294 * @since 6172 1288 1295 */ … … 1290 1297 CheckParameterUtil.ensureParameterNotNull(img, "img"); 1291 1298 1292 1299 // 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 } 1300 Long angleLong = Math.round(rotatedAngle % 360); 1301 Long originalAngle = rotatedAngle != 0 && angleLong == 0 ? 360L : angleLong; 1297 1302 1298 ImageResource imageResource;1299 1300 1303 synchronized (ROTATE_CACHE) { 1301 Map<Long, Image Resource> cacheByAngle = ROTATE_CACHE.get(img);1304 Map<Long, Image> cacheByAngle = ROTATE_CACHE.get(img); 1302 1305 if (cacheByAngle == null) { 1303 1306 cacheByAngle = new HashMap<>(); 1304 1307 ROTATE_CACHE.put(img, cacheByAngle); 1305 1308 } 1306 1309 1307 imageResource= cacheByAngle.get(originalAngle);1310 Image rotatedImg = cacheByAngle.get(originalAngle); 1308 1311 1309 if ( imageResource== null) {1312 if (rotatedImg == null) { 1310 1313 // convert originalAngle to a value from 0 to 90 1311 1314 double angle = originalAngle % 90; 1312 1315 if (originalAngle != 0 && angle == 0) { 1313 1316 angle = 90.0; 1314 1317 } 1315 1316 1318 double radian = Utils.toRadians(angle); 1317 1319 1318 new ImageIcon(img); // load completely 1319 int iw = img.getWidth(null); 1320 int ih = img.getHeight(null); 1321 int w; 1322 int h; 1320 rotatedImg = HiDPISupport.processMRImage(img, img0 -> { 1321 new ImageIcon(img0); // load completely 1322 int iw = img0.getWidth(null); 1323 int ih = img0.getHeight(null); 1324 int w; 1325 int h; 1323 1326 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(); 1327 if ((originalAngle >= 0 && originalAngle <= 90) || (originalAngle > 180 && originalAngle <= 270)) { 1328 w = (int) (iw * Math.sin(DEGREE_90 - radian) + ih * Math.sin(radian)); 1329 h = (int) (iw * Math.sin(radian) + ih * Math.sin(DEGREE_90 - radian)); 1330 } else { 1331 w = (int) (ih * Math.sin(DEGREE_90 - radian) + iw * Math.sin(radian)); 1332 h = (int) (ih * Math.sin(radian) + iw * Math.sin(DEGREE_90 - radian)); 1333 } 1334 Image image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); 1335 Graphics g = image.getGraphics(); 1336 Graphics2D g2d = (Graphics2D) g.create(); 1336 1337 1337 // calculate the center of the icon.1338 int cx = iw / 2;1339 int cy = ih / 2;1338 // calculate the center of the icon. 1339 int cx = iw / 2; 1340 int cy = ih / 2; 1340 1341 1341 // move the graphics center point to the center of the icon.1342 g2d.translate(w / 2, h / 2);1342 // move the graphics center point to the center of the icon. 1343 g2d.translate(w / 2, h / 2); 1343 1344 1344 // rotate the graphics about the center point of the icon1345 g2d.rotate(Utils.toRadians(originalAngle));1345 // rotate the graphics about the center point of the icon 1346 g2d.rotate(Utils.toRadians(originalAngle)); 1346 1347 1347 g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);1348 g2d.drawImage(img, -cx, -cy, null);1348 g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); 1349 g2d.drawImage(img0, -cx, -cy, null); 1349 1350 1350 g2d.dispose(); 1351 new ImageIcon(image); // load completely 1351 g2d.dispose(); 1352 new ImageIcon(image); // load completely 1353 return image; 1354 }); 1355 cacheByAngle.put(originalAngle, rotatedImg); 1352 1356 } 1353 return imageResource.getImageIcon(dimension).getImage();1357 return rotatedImg; 1354 1358 } 1355 1359 } 1356 1360 … … 1411 1415 BufferedImage.TYPE_INT_ARGB); 1412 1416 double scaleFactor = Math.min(backgroundRealWidth / (double) iconRealWidth, backgroundRealHeight 1413 1417 / (double) iconRealHeight); 1414 BufferedImage iconImage = icon.getImage(false);1418 Image iconImage = icon.getImage(false); 1415 1419 Image scaledIcon; 1416 1420 final int scaledWidth; 1417 1421 final int scaledHeight; -
src/org/openstreetmap/josm/tools/ImageResource.java
156 156 * @return ImageIcon object for the image of this resource, scaled according to dim 157 157 */ 158 158 public ImageIcon getImageIcon(Dimension dim) { 159 return getImageIcon(dim, true); 160 } 161 162 public ImageIcon getImageIcon(Dimension dim, boolean multiResolution) { 163 ImageIcon img0 = getImageIconBasic(dim); 164 if (!multiResolution) 165 return img0; 166 try { 167 Image mrImg = HiDPISupport.getMultiResolutionImage(img0.getImage(), this); 168 return new ImageIcon(mrImg); 169 } catch (NoClassDefFoundError e) { 170 return img0; 171 } 172 } 173 174 ImageIcon getImageIconBasic(Dimension dim) { 159 175 if (dim.width < -1 || dim.width == 0 || dim.height < -1 || dim.height == 0) 160 176 throw new IllegalArgumentException(dim+" is invalid"); 161 177 Image img = imgCache.get(dim); … … 216 232 * @return ImageIcon object for the image of this resource, scaled down if needed, according to maxSize 217 233 */ 218 234 public ImageIcon getImageIconBounded(Dimension maxSize) { 235 return getImageIconBounded(maxSize, true); 236 } 237 238 public ImageIcon getImageIconBounded(Dimension maxSize, boolean multiResolution) { 219 239 if (maxSize.width < -1 || maxSize.width == 0 || maxSize.height < -1 || maxSize.height == 0) 220 240 throw new IllegalArgumentException(maxSize+" is invalid"); 221 241 float sourceWidth; … … 239 259 } 240 260 241 261 if (maxWidth == -1 && maxHeight == -1) 242 return getImageIcon(DEFAULT_DIMENSION );262 return getImageIcon(DEFAULT_DIMENSION, multiResolution); 243 263 else if (maxWidth == -1) 244 return getImageIcon(new Dimension(-1, maxHeight) );264 return getImageIcon(new Dimension(-1, maxHeight), multiResolution); 245 265 else if (maxHeight == -1) 246 return getImageIcon(new Dimension(maxWidth, -1) );266 return getImageIcon(new Dimension(maxWidth, -1), multiResolution); 247 267 else if (sourceWidth / maxWidth > sourceHeight / maxHeight) 248 return getImageIcon(new Dimension(maxWidth, -1) );268 return getImageIcon(new Dimension(maxWidth, -1), multiResolution); 249 269 else 250 return getImageIcon(new Dimension(-1, maxHeight) );270 return getImageIcon(new Dimension(-1, maxHeight), multiResolution); 251 271 } 252 272 }