Changeset 12722 in josm for trunk/src/org/openstreetmap/josm/tools
- Timestamp:
- 2017-09-04T18:52:06+02:00 (7 years ago)
- Location:
- trunk/src/org/openstreetmap/josm/tools
- Files:
-
- 1 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/tools/ImageOverlay.java
r9078 r12722 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; -
trunk/src/org/openstreetmap/josm/tools/ImageProvider.java
r12682 r12722 277 277 /** <code>true</code> if icon must be grayed out */ 278 278 protected boolean isDisabled; 279 /** <code>true</code> if multi-resolution image is requested */ 280 protected boolean multiResolution = true; 279 281 280 282 private static SVGUniverse svgUniverse; … … 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 = … … 334 336 this.overlayInfo = image.overlayInfo; 335 337 this.isDisabled = image.isDisabled; 338 this.multiResolution = image.multiResolution; 336 339 } 337 340 … … 596 599 597 600 /** 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 /** 598 623 * Execute the image request and scale result. 599 624 * @return the requested image or null if the request failed … … 606 631 } 607 632 if (virtualMaxWidth != -1 || virtualMaxHeight != -1) 608 return ir.getImageIconBounded(new Dimension(virtualMaxWidth, virtualMaxHeight) );633 return ir.getImageIconBounded(new Dimension(virtualMaxWidth, virtualMaxHeight), multiResolution); 609 634 else 610 return ir.getImageIcon(new Dimension(virtualWidth, virtualHeight) );635 return ir.getImageIcon(new Dimension(virtualWidth, virtualHeight), multiResolution); 611 636 } 612 637 … … 1276 1301 1277 1302 /** 1278 * Creates a rotated version of the input image , scaled to the given dimension.1303 * Creates a rotated version of the input image. 1279 1304 * 1280 1305 * @param img the image to be rotated. … … 1282 1307 * will mod it with 360 before using it. More over for caching performance, it will be rounded to 1283 1308 * 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 1286 1310 * @return the image after rotating and scaling. 1287 1311 * @since 6172 … … 1291 1315 1292 1316 // 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; 1299 1319 1300 1320 synchronized (ROTATE_CACHE) { 1301 Map<Long, Image Resource> cacheByAngle = ROTATE_CACHE.get(img);1321 Map<Long, Image> cacheByAngle = ROTATE_CACHE.get(img); 1302 1322 if (cacheByAngle == null) { 1303 1323 cacheByAngle = new HashMap<>(); … … 1305 1325 } 1306 1326 1307 imageResource= cacheByAngle.get(originalAngle);1308 1309 if ( imageResource== null) {1327 Image rotatedImg = cacheByAngle.get(originalAngle); 1328 1329 if (rotatedImg == null) { 1310 1330 // convert originalAngle to a value from 0 to 90 1311 1331 double angle = originalAngle % 90; … … 1313 1333 angle = 90.0; 1314 1334 } 1315 1316 1335 double radian = Utils.toRadians(angle); 1317 1336 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; 1354 1375 } 1355 1376 } … … 1412 1433 double scaleFactor = Math.min(backgroundRealWidth / (double) iconRealWidth, backgroundRealHeight 1413 1434 / (double) iconRealHeight); 1414 BufferedImage iconImage = icon.getImage(false);1435 Image iconImage = icon.getImage(false); 1415 1436 Image scaledIcon; 1416 1437 final int scaledWidth; -
trunk/src/org/openstreetmap/josm/tools/ImageResource.java
r12682 r12722 31 31 * Caches the image data for resized versions of the same image. 32 32 */ 33 private final Map<Dimension, Image> imgCache = new HashMap<>();33 private final Map<Dimension, BufferedImage> imgCache = new HashMap<>(); 34 34 /** 35 35 * SVG diagram information in case of SVG vector image. … … 151 151 152 152 /** 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). 154 156 * @param dim The requested dimensions. Use (-1,-1) for the original size and (width, -1) 155 157 * to set the width, but otherwise scale the image proportionally. 158 * @see #getImageIconBounded(java.awt.Dimension, boolean) 156 159 * @return ImageIcon object for the image of this resource, scaled according to dim 157 160 */ 158 161 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) { 159 176 if (dim.width < -1 || dim.width == 0 || dim.height < -1 || dim.height == 0) 160 177 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) 163 224 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 } 208 233 } 209 234 … … 211 236 * Get image icon with a certain maximum size. The image is scaled down 212 237 * to fit maximum dimensions. (Keeps aspect ratio) 238 * <p> 239 * Will return a multi-resolution image by default (if possible). 213 240 * 214 241 * @param maxSize The maximum size. One of the dimensions (width or height) can be -1, 215 242 * which means it is not bounded. 216 243 * @return ImageIcon object for the image of this resource, scaled down if needed, according to maxSize 244 * @see #getImageIconBounded(java.awt.Dimension, boolean) 217 245 */ 218 246 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) { 219 263 if (maxSize.width < -1 || maxSize.width == 0 || maxSize.height < -1 || maxSize.height == 0) 220 264 throw new IllegalArgumentException(maxSize+" is invalid"); … … 240 284 241 285 if (maxWidth == -1 && maxHeight == -1) 242 return getImageIcon(DEFAULT_DIMENSION );286 return getImageIcon(DEFAULT_DIMENSION, multiResolution); 243 287 else if (maxWidth == -1) 244 return getImageIcon(new Dimension(-1, maxHeight) );288 return getImageIcon(new Dimension(-1, maxHeight), multiResolution); 245 289 else if (maxHeight == -1) 246 return getImageIcon(new Dimension(maxWidth, -1) );290 return getImageIcon(new Dimension(maxWidth, -1), multiResolution); 247 291 else if (sourceWidth / maxWidth > sourceHeight / maxHeight) 248 return getImageIcon(new Dimension(maxWidth, -1) );292 return getImageIcon(new Dimension(maxWidth, -1), multiResolution); 249 293 else 250 return getImageIcon(new Dimension(-1, maxHeight) );294 return getImageIcon(new Dimension(-1, maxHeight), multiResolution); 251 295 } 252 296 }
Note:
See TracChangeset
for help on using the changeset viewer.