Changeset 16946 in josm
- Timestamp:
- 2020-08-28T20:16:25+02:00 (4 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/tools/HiDPISupport.java
r16877 r16946 54 54 * @param base the base image 55 55 * @param ir a corresponding image resource 56 * @param resizeMode how to size/resize the image 56 57 * @return multi-resolution image if necessary and possible, the base image otherwise 57 58 */ 58 public static Image getMultiResolutionImage(Image base, ImageResource ir ) {59 public static Image getMultiResolutionImage(Image base, ImageResource ir, ImageResizeMode resizeMode) { 59 60 double uiScale = getHiDPIScale(); 60 61 if (uiScale != 1.0 && baseMultiResolutionImageConstructor != null) { 61 62 ImageIcon zoomed = ir.getImageIconAlreadyScaled(new Dimension( 62 63 (int) Math.round(base.getWidth(null) * uiScale), 63 (int) Math.round(base.getHeight(null) * uiScale)), false, true );64 (int) Math.round(base.getHeight(null) * uiScale)), false, true, resizeMode); 64 65 Image mrImg = getMultiResolutionImage(Arrays.asList(base, zoomed.getImage())); 65 66 if (mrImg != null) return mrImg; -
trunk/src/org/openstreetmap/josm/tools/ImageProvider.java
r16924 r16946 660 660 } 661 661 if (virtualMaxWidth != -1 || virtualMaxHeight != -1) 662 return ir.getImageIcon Bounded(new Dimension(virtualMaxWidth, virtualMaxHeight), multiResolution);662 return ir.getImageIcon(new Dimension(virtualMaxWidth, virtualMaxHeight), multiResolution, ImageResizeMode.BOUNDED); 663 663 else 664 return ir.getImageIcon(new Dimension(virtualWidth, virtualHeight), multiResolution );664 return ir.getImageIcon(new Dimension(virtualWidth, virtualHeight), multiResolution, ImageResizeMode.AUTO); 665 665 } 666 666 … … 1472 1472 } 1473 1473 1474 static BufferedImage createPaddedIcon(Image icon, Dimension iconSize) {1475 int backgroundRealWidth = GuiSizesHelper.getSizeDpiAdjusted(iconSize.width);1476 int backgroundRealHeight = GuiSizesHelper.getSizeDpiAdjusted(iconSize.height);1477 int iconRealWidth = icon.getWidth(null);1478 int iconRealHeight = icon.getHeight(null);1479 BufferedImage image = new BufferedImage(backgroundRealWidth, backgroundRealHeight, BufferedImage.TYPE_INT_ARGB);1480 double scaleFactor = Math.min(1481 backgroundRealWidth / (double) iconRealWidth,1482 backgroundRealHeight / (double) iconRealHeight);1483 Image scaledIcon;1484 final int scaledWidth;1485 final int scaledHeight;1486 if (scaleFactor < 1) {1487 // Scale icon such that it fits on background.1488 scaledWidth = (int) (iconRealWidth * scaleFactor);1489 scaledHeight = (int) (iconRealHeight * scaleFactor);1490 scaledIcon = icon.getScaledInstance(scaledWidth, scaledHeight, Image.SCALE_SMOOTH);1491 } else {1492 // Use original size, don't upscale.1493 scaledWidth = iconRealWidth;1494 scaledHeight = iconRealHeight;1495 scaledIcon = icon;1496 }1497 image.getGraphics().drawImage(scaledIcon,1498 (backgroundRealWidth - scaledWidth) / 2,1499 (backgroundRealHeight - scaledHeight) / 2, null);1500 1501 return image;1502 }1503 1504 1474 /** 1505 1475 * Constructs an image from the given SVG data. 1506 1476 * @param svg the SVG data 1507 1477 * @param dim the desired image dimension 1478 * @param resizeMode how to size/resize the image 1508 1479 * @return an image from the given SVG data at the desired dimension. 1509 1480 */ 1510 public static BufferedImage createImageFromSvg(SVGDiagram svg, Dimension dim) {1481 static BufferedImage createImageFromSvg(SVGDiagram svg, Dimension dim, ImageResizeMode resizeMode) { 1511 1482 if (Logging.isTraceEnabled()) { 1512 1483 Logging.trace("createImageFromSvg: {0} {1}", svg.getXMLBase(), dim); … … 1514 1485 final float sourceWidth = svg.getWidth(); 1515 1486 final float sourceHeight = svg.getHeight(); 1516 final float realWidth; 1517 final float realHeight; 1518 if (dim.width >= 0) { 1519 realWidth = dim.width; 1520 if (dim.height >= 0) { 1521 realHeight = dim.height; 1522 } else { 1523 realHeight = sourceHeight * realWidth / sourceWidth; 1524 } 1525 } else if (dim.height >= 0) { 1526 realHeight = dim.height; 1527 realWidth = sourceWidth * realHeight / sourceHeight; 1528 } else { 1529 realWidth = GuiSizesHelper.getSizeDpiAdjusted(sourceWidth); 1530 realHeight = GuiSizesHelper.getSizeDpiAdjusted(sourceHeight); 1531 } 1532 1533 int roundedWidth = Math.round(realWidth); 1534 int roundedHeight = Math.round(realHeight); 1535 if (roundedWidth <= 0 || roundedHeight <= 0 || roundedWidth >= Integer.MAX_VALUE || roundedHeight >= Integer.MAX_VALUE) { 1536 Logging.error("createImageFromSvg: {0} {1} realWidth={2} realHeight={3}", 1537 svg.getXMLBase(), dim, Float.toString(realWidth), Float.toString(realHeight)); 1487 if (sourceWidth <= 0 || sourceHeight <= 0) { 1488 Logging.error("createImageFromSvg: {0} {1} sourceWidth={2} sourceHeight={3}", svg.getXMLBase(), dim, sourceWidth, sourceHeight); 1538 1489 return null; 1539 1490 } 1540 BufferedImage img = new BufferedImage(roundedWidth, roundedHeight, BufferedImage.TYPE_INT_ARGB); 1541 Graphics2D g = img.createGraphics(); 1542 g.setClip(0, 0, img.getWidth(), img.getHeight()); 1543 g.scale(realWidth / sourceWidth, realHeight / sourceHeight); 1544 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 1545 try { 1546 synchronized (getSvgUniverse()) { 1547 svg.render(g); 1548 } 1549 } catch (SVGException ex) { 1550 Logging.log(Logging.LEVEL_ERROR, "Unable to load svg:", ex); 1551 return null; 1552 } 1553 return img; 1491 return resizeMode.createBufferedImage(dim, new Dimension((int) sourceWidth, (int) sourceHeight), g -> { 1492 try { 1493 synchronized (getSvgUniverse()) { 1494 svg.render(g); 1495 } 1496 } catch (SVGException ex) { 1497 Logging.log(Logging.LEVEL_ERROR, "Unable to load svg:", ex); 1498 } 1499 }); 1554 1500 } 1555 1501 -
trunk/src/org/openstreetmap/josm/tools/ImageResource.java
r16926 r16946 29 29 30 30 /** 31 * Caches the image data for resized versions of the same image. 32 */ 33 private final Map< Dimension, BufferedImage> imgCache = new ConcurrentHashMap<>(4);31 * Caches the image data for resized versions of the same image. The key is obtained using {@link ImageResizeMode#cacheKey(Dimension)}. 32 */ 33 private final Map<Integer, BufferedImage> imgCache = new ConcurrentHashMap<>(4); 34 34 /** 35 35 * SVG diagram information in case of SVG vector image. … … 138 138 * to set the width, but otherwise scale the image proportionally. 139 139 * @return ImageIcon object for the image of this resource, scaled according to dim 140 * @see #getImageIconBounded(java.awt.Dimension , boolean)140 * @see #getImageIconBounded(java.awt.Dimension) 141 141 */ 142 142 public ImageIcon getImageIcon(Dimension dim) { 143 return getImageIcon(dim, true );143 return getImageIcon(dim, true, ImageResizeMode.AUTO); 144 144 } 145 145 … … 151 151 * (java.awt.image.MultiResolutionImage in Java 9), otherwise a plain {@link BufferedImage}. 152 152 * When running Java 8, this flag has no effect and a plain image will be returned in any case. 153 * @param resizeMode how to size/resize the image 153 154 * @return ImageIcon object for the image of this resource, scaled according to dim 154 155 * @since 12722 155 156 */ 156 ImageIcon getImageIcon(Dimension dim, boolean multiResolution ) {157 return getImageIconAlreadyScaled(GuiSizesHelper.getDimensionDpiAdjusted(dim), multiResolution, false );157 ImageIcon getImageIcon(Dimension dim, boolean multiResolution, ImageResizeMode resizeMode) { 158 return getImageIconAlreadyScaled(GuiSizesHelper.getDimensionDpiAdjusted(dim), multiResolution, false, resizeMode); 158 159 } 159 160 … … 167 168 * When running Java 8, this flag has no effect and a plain image will be returned in any case. 168 169 * @param highResolution whether the high resolution variant should be used for overlays 170 * @param resizeMode how to size/resize the image 169 171 * @return ImageIcon object for the image of this resource, scaled according to dim 170 172 */ 171 ImageIcon getImageIconAlreadyScaled(Dimension dim, boolean multiResolution, boolean highResolution ) {173 ImageIcon getImageIconAlreadyScaled(Dimension dim, boolean multiResolution, boolean highResolution, ImageResizeMode resizeMode) { 172 174 CheckParameterUtil.ensureThat((dim.width > 0 || dim.width == -1) && (dim.height > 0 || dim.height == -1), 173 175 () -> dim + " is invalid"); 174 176 175 BufferedImage img = imgCache.get(dim); 177 final int cacheKey = resizeMode.cacheKey(dim); 178 BufferedImage img = imgCache.get(cacheKey); 176 179 if (img == null) { 177 180 if (svg != null) { 178 img = ImageProvider.createImageFromSvg(svg, dim );181 img = ImageProvider.createImageFromSvg(svg, dim, resizeMode); 179 182 if (img == null) { 180 183 return null; … … 182 185 } else { 183 186 if (baseImage == null) throw new AssertionError(); 184 185 187 ImageIcon icon = new ImageIcon(baseImage); 186 if (dim.width == -1 && dim.height == -1) { 187 dim.width = GuiSizesHelper.getSizeDpiAdjusted(icon.getIconWidth()); 188 dim.height = GuiSizesHelper.getSizeDpiAdjusted(icon.getIconHeight()); 189 } else if (dim.width == -1) { 190 dim.width = Math.max(1, icon.getIconWidth() * dim.height / icon.getIconHeight()); 191 } else if (dim.height == -1) { 192 dim.height = Math.max(1, icon.getIconHeight() * dim.width / icon.getIconWidth()); 193 } 194 Image i = icon.getImage().getScaledInstance(dim.width, dim.height, Image.SCALE_SMOOTH); 195 img = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_ARGB); 196 img.getGraphics().drawImage(i, 0, 0, null); 188 img = resizeMode.createBufferedImage(dim, new Dimension(icon.getIconWidth(), icon.getIconHeight()), 189 g -> g.drawImage(icon.getImage(), 0, 0, null)); 197 190 } 198 191 if (overlayInfo != null) { … … 212 205 disabledIcon.paintIcon(new JPanel(), img.getGraphics(), 0, 0); 213 206 } 214 imgCache.put( dim, img);207 imgCache.put(cacheKey, img); 215 208 } 216 209 … … 219 212 else { 220 213 try { 221 Image mrImg = HiDPISupport.getMultiResolutionImage(img, this );214 Image mrImg = HiDPISupport.getMultiResolutionImage(img, this, resizeMode); 222 215 return new ImageIcon(mrImg); 223 216 } catch (NoClassDefFoundError e) { … … 237 230 * which means it is not bounded. 238 231 * @return ImageIcon object for the image of this resource, scaled down if needed, according to maxSize 239 * @see #getImageIconBounded(java.awt.Dimension, boolean)240 232 */ 241 233 public ImageIcon getImageIconBounded(Dimension maxSize) { 242 return getImageIconBounded(maxSize, true); 243 } 244 245 /** 246 * Get image icon with a certain maximum size. The image is scaled down 247 * to fit maximum dimensions. (Keeps aspect ratio) 248 * 249 * @param maxSize The maximum size. One of the dimensions (width or height) can be -1, 250 * which means it is not bounded. 251 * @param multiResolution If true, return a multi-resolution image 252 * (java.awt.image.MultiResolutionImage in Java 9), otherwise a plain {@link BufferedImage}. 253 * When running Java 8, this flag has no effect and a plain image will be returned in any case. 254 * @return ImageIcon object for the image of this resource, scaled down if needed, according to maxSize 255 * @since 12722 256 */ 257 public ImageIcon getImageIconBounded(Dimension maxSize, boolean multiResolution) { 258 CheckParameterUtil.ensureThat((maxSize.width > 0 || maxSize.width == -1) && (maxSize.height > 0 || maxSize.height == -1), 259 () -> maxSize + " is invalid"); 260 float sourceWidth; 261 float sourceHeight; 262 int maxWidth = maxSize.width; 263 int maxHeight = maxSize.height; 264 if (svg != null) { 265 sourceWidth = svg.getWidth(); 266 sourceHeight = svg.getHeight(); 267 } else { 268 if (baseImage == null) throw new AssertionError(); 269 ImageIcon icon = new ImageIcon(baseImage); 270 sourceWidth = icon.getIconWidth(); 271 sourceHeight = icon.getIconHeight(); 272 if (sourceWidth <= maxWidth) { 273 maxWidth = -1; 274 } 275 if (sourceHeight <= maxHeight) { 276 maxHeight = -1; 277 } 278 } 279 280 if (maxWidth == -1 && maxHeight == -1) 281 return getImageIcon(DEFAULT_DIMENSION, multiResolution); 282 else if (maxWidth == -1) 283 return getImageIcon(new Dimension(-1, maxHeight), multiResolution); 284 else if (maxHeight == -1) 285 return getImageIcon(new Dimension(maxWidth, -1), multiResolution); 286 else if (sourceWidth / maxWidth > sourceHeight / maxHeight) 287 return getImageIcon(new Dimension(maxWidth, -1), multiResolution); 288 else 289 return getImageIcon(new Dimension(-1, maxHeight), multiResolution); 234 return getImageIcon(maxSize, true, ImageResizeMode.BOUNDED); 290 235 } 291 236 … … 297 242 */ 298 243 public ImageIcon getPaddedIcon(Dimension iconSize) { 299 final ImageIcon imageIcon = getImageIcon(iconSize); 300 if (imageIcon.getIconWidth() == iconSize.width && imageIcon.getIconHeight() == iconSize.height) { 301 // fast path for square and svg icons 302 return imageIcon; 303 } 304 305 final Dimension cacheKey = new Dimension(-iconSize.width, -iconSize.height); // use negative width/height for differentiation 306 BufferedImage image = imgCache.get(cacheKey); 307 if (image == null) { 308 image = ImageProvider.createPaddedIcon(getImageIcon().getImage(), iconSize); 309 imgCache.put(cacheKey, image); 310 } 311 return new ImageIcon(image); 244 return getImageIcon(iconSize, true, ImageResizeMode.PADDED); 312 245 } 313 246 -
trunk/test/unit/org/openstreetmap/josm/tools/OsmPrimitiveImageProviderTest.java
r16926 r16946 61 61 assertNotNull(OsmPrimitiveImageProvider.getResource(OsmUtils.createPrimitive("way waterway=stream"), noDefault)); 62 62 assertNotNull(OsmPrimitiveImageProvider.getResource(OsmUtils.createPrimitive("relation type=route route=railway"), noDefault)); 63 // a non-square svg icon 63 } 64 65 /** 66 * Unit test of {@link OsmPrimitiveImageProvider#getResource} for non-square images. 67 */ 68 @Test 69 public void testGetResourceNonSquare() { 64 70 final ImageIcon bankIcon = OsmPrimitiveImageProvider 65 71 .getResource(OsmUtils.createPrimitive("node amenity=bank"), Options.DEFAULT) … … 67 73 assertEquals(ImageProvider.ImageSizes.LARGEICON.getVirtualWidth(), bankIcon.getIconWidth()); 68 74 assertEquals(ImageProvider.ImageSizes.LARGEICON.getVirtualHeight(), bankIcon.getIconHeight()); 75 final ImageIcon addressIcon = OsmPrimitiveImageProvider 76 .getResource(OsmUtils.createPrimitive("node \"addr:housenumber\"=123"), Options.DEFAULT) 77 .getPaddedIcon(ImageProvider.ImageSizes.LARGEICON.getImageDimension()); 78 assertEquals(ImageProvider.ImageSizes.LARGEICON.getVirtualWidth(), addressIcon.getIconWidth()); 79 assertEquals(ImageProvider.ImageSizes.LARGEICON.getVirtualHeight(), addressIcon.getIconHeight()); 69 80 } 70 81 }
Note:
See TracChangeset
for help on using the changeset viewer.