diff --git a/src/org/openstreetmap/josm/gui/mappaint/styleelement/MapImage.java b/src/org/openstreetmap/josm/gui/mappaint/styleelement/MapImage.java
index 963b42bab..c921a2217 100644
a
|
b
|
private Image getImage() {
|
189 | 189 | ImageIcon noIcon = MapPaintStyles.getNoIconIcon(source); |
190 | 190 | img = noIcon == null ? null : noIcon.getImage(); |
191 | 191 | } else { |
192 | | img = rescale(result.getImageIcon(new Dimension(width, height)).getImage()); |
| 192 | img = result.getImageIcon(new Dimension(width, height)).getImage(); |
| 193 | if (img != null && mustRescale(img)) { |
| 194 | // Scale down large images to 16x16 pixels if no size is explicitly specified |
| 195 | img = result.getImageIconBounded(ImageProvider.ImageSizes.MAP.getImageDimension()).getImage(); |
| 196 | } |
193 | 197 | } |
194 | 198 | if (temporary) { |
195 | 199 | disabledImgCache = null; |
… |
… |
public BoxProvider getBoxProvider() {
|
300 | 304 | return new MapImageBoxProvider(); |
301 | 305 | } |
302 | 306 | |
303 | | /** |
304 | | * Rescale excessively large images. |
305 | | * @param image the unscaled image |
306 | | * @return The scaled down version to 16x16 pixels if the image height and width exceeds 48 pixels and no size has been explicitly specified |
307 | | */ |
308 | | private Image rescale(Image image) { |
309 | | if (image == null) return null; |
310 | | // Scale down large (.svg) images to 16x16 pixels if no size is explicitly specified |
311 | | if (mustRescale(image)) { |
312 | | return ImageProvider.createBoundedImage(image, 16); |
313 | | } else { |
314 | | return image; |
315 | | } |
316 | | } |
317 | | |
318 | 307 | private boolean mustRescale(Image image) { |
319 | 308 | return autoRescale && width == -1 && image.getWidth(null) > MAX_SIZE |
320 | 309 | && height == -1 && image.getHeight(null) > MAX_SIZE; |
diff --git a/src/org/openstreetmap/josm/tools/ImageProvider.java b/src/org/openstreetmap/josm/tools/ImageProvider.java
index 29a55dbe6..67d424bcd 100644
a
|
b
|
public ImageIcon get() {
|
660 | 660 | Logging.trace("get {0} from {1}", this, Thread.currentThread()); |
661 | 661 | } |
662 | 662 | if (virtualMaxWidth != -1 || virtualMaxHeight != -1) |
663 | | return ir.getImageIcon(new Dimension(virtualMaxWidth, virtualMaxHeight), multiResolution, ImageResizeMode.BOUNDED); |
| 663 | return ir.getImageIcon(new Dimension(virtualMaxWidth, virtualMaxHeight), multiResolution, null); |
664 | 664 | else |
665 | 665 | return ir.getImageIcon(new Dimension(virtualWidth, virtualHeight), multiResolution, ImageResizeMode.AUTO); |
666 | 666 | } |
… |
… |
static BufferedImage createImageFromSvg(SVGDiagram svg, Dimension dim, ImageResi
|
1489 | 1489 | Logging.error("createImageFromSvg: {0} {1} sourceWidth={2} sourceHeight={3}", svg.getXMLBase(), dim, sourceWidth, sourceHeight); |
1490 | 1490 | return null; |
1491 | 1491 | } |
1492 | | if (resizeMode == ImageResizeMode.BOUNDED) { |
1493 | | resizeMode = ImageResizeMode.BOUNDED_UPSCALE; |
1494 | | } |
1495 | 1492 | return resizeMode.createBufferedImage(dim, new Dimension((int) sourceWidth, (int) sourceHeight), g -> { |
1496 | 1493 | try { |
1497 | 1494 | synchronized (getSvgUniverse()) { |
diff --git a/src/org/openstreetmap/josm/tools/ImageResizeMode.java b/src/org/openstreetmap/josm/tools/ImageResizeMode.java
index 2ea8d1e68..d1bcabc2a 100644
a
|
b
|
|
13 | 13 | */ |
14 | 14 | enum ImageResizeMode { |
15 | 15 | |
| 16 | /** |
| 17 | * Calculate proportional dimensions that best fit into the target width and height, retain aspect ratio |
| 18 | */ |
16 | 19 | AUTO { |
17 | 20 | @Override |
18 | 21 | Dimension computeDimension(Dimension dim, Dimension icon) { |
… |
… |
Dimension computeDimension(Dimension dim, Dimension icon) {
|
24 | 27 | return new Dimension(Math.max(1, icon.width * dim.height / icon.height), dim.height); |
25 | 28 | } else if (dim.height == -1) { |
26 | 29 | return new Dimension(dim.width, Math.max(1, icon.height * dim.width / icon.width)); |
| 30 | } else if (icon.getWidth() / dim.getWidth() > icon.getHeight() / dim.getHeight()) { |
| 31 | return computeDimension(new Dimension(dim.width, -1), icon); |
27 | 32 | } else { |
28 | | return dim; |
| 33 | return computeDimension(new Dimension(-1, dim.height), icon); |
29 | 34 | } |
30 | 35 | } |
31 | 36 | }, |
32 | 37 | |
| 38 | /** |
| 39 | * Calculate dimensions for the largest image that fit within the bounding box, retain aspect ratio |
| 40 | */ |
33 | 41 | BOUNDED { |
34 | | @Override |
35 | | Dimension computeDimension(Dimension dim, Dimension icon) { |
36 | | final int maxWidth = Math.min(dim.width, icon.width); |
37 | | final int maxHeight = Math.min(dim.height, icon.height); |
38 | | return BOUNDED_UPSCALE.computeDimension(new Dimension(maxWidth, maxHeight), icon); |
39 | | } |
40 | | }, |
41 | | |
42 | | BOUNDED_UPSCALE { |
43 | 42 | @Override |
44 | 43 | Dimension computeDimension(Dimension dim, Dimension icon) { |
45 | 44 | CheckParameterUtil.ensureThat((dim.width > 0 || dim.width == -1) && (dim.height > 0 || dim.height == -1), |
46 | 45 | () -> dim + " is invalid"); |
47 | | final int maxWidth = dim.width; |
48 | | final int maxHeight = dim.height; |
49 | | final Dimension spec; |
50 | | if (maxWidth == -1 || maxHeight == -1) { |
51 | | spec = dim; |
52 | | } else if (icon.getWidth() / maxWidth > icon.getHeight() / maxHeight) { |
53 | | spec = new Dimension(maxWidth, -1); |
54 | | } else { |
55 | | spec = new Dimension(-1, maxHeight); |
56 | | } |
57 | | return AUTO.computeDimension(spec, icon); |
| 46 | final int maxWidth = Math.min(dim.width, icon.width); |
| 47 | final int maxHeight = Math.min(dim.height, icon.height); |
| 48 | return AUTO.computeDimension(new Dimension(maxWidth, maxHeight), icon); |
58 | 49 | } |
59 | 50 | }, |
60 | 51 | |
| 52 | /** |
| 53 | * Position an appropriately scaled image within the bounding box, retain aspect ratio |
| 54 | */ |
61 | 55 | PADDED { |
62 | 56 | @Override |
63 | 57 | Dimension computeDimension(Dimension dim, Dimension icon) { |
diff --git a/src/org/openstreetmap/josm/tools/ImageResource.java b/src/org/openstreetmap/josm/tools/ImageResource.java
index 59d9834d1..f710b7f30 100644
a
|
b
|
public ImageResource setDisabled(boolean disabled) {
|
101 | 101 | */ |
102 | 102 | public void attachImageIcon(AbstractAction a) { |
103 | 103 | Dimension iconDimension = ImageProvider.ImageSizes.SMALLICON.getImageDimension(); |
104 | | ImageIcon icon = getImageIconBounded(iconDimension); |
| 104 | ImageIcon icon = getImageIcon(iconDimension); |
105 | 105 | a.putValue(Action.SMALL_ICON, icon); |
106 | 106 | |
107 | 107 | iconDimension = ImageProvider.ImageSizes.LARGEICON.getImageDimension(); |
108 | | icon = getImageIconBounded(iconDimension); |
| 108 | icon = getImageIcon(iconDimension); |
109 | 109 | a.putValue(Action.LARGE_ICON_KEY, icon); |
110 | 110 | } |
111 | 111 | |
… |
… |
public ImageIcon getImageIcon() {
|
140 | 140 | * @see #getImageIconBounded(java.awt.Dimension) |
141 | 141 | */ |
142 | 142 | public ImageIcon getImageIcon(Dimension dim) { |
143 | | return getImageIcon(dim, true, ImageResizeMode.AUTO); |
| 143 | return getImageIcon(dim, true, null); |
144 | 144 | } |
145 | 145 | |
146 | 146 | /** |
… |
… |
ImageIcon getImageIconAlreadyScaled(Dimension dim, boolean multiResolution, bool
|
174 | 174 | CheckParameterUtil.ensureThat((dim.width > 0 || dim.width == -1) && (dim.height > 0 || dim.height == -1), |
175 | 175 | () -> dim + " is invalid"); |
176 | 176 | |
| 177 | if (resizeMode == null && svg != null) { |
| 178 | // upscale SVG icons |
| 179 | resizeMode = ImageResizeMode.AUTO; |
| 180 | } else if (resizeMode == null) { |
| 181 | resizeMode = ImageResizeMode.BOUNDED; |
| 182 | } |
177 | 183 | final int cacheKey = resizeMode.cacheKey(dim); |
178 | 184 | BufferedImage img = imgCache.get(cacheKey); |
179 | 185 | if (img == null) { |
diff --git a/test/functional/org/openstreetmap/josm/tools/ImageProviderTest.java b/test/functional/org/openstreetmap/josm/tools/ImageProviderTest.java
index e4b0bd20e..a318f11c2 100644
a
|
b
|
public void testImageIcon() throws IOException {
|
170 | 170 | ImageResource resource = new ImageProvider("presets/misc/housenumber_small").getResource(); |
171 | 171 | testImage(12, 9, "housenumber_small-AUTO-null", resource.getImageIcon()); |
172 | 172 | testImage(12, 9, "housenumber_small-AUTO-default", resource.getImageIcon(ImageResource.DEFAULT_DIMENSION)); |
173 | | testImage(8, 8, "housenumber_small-AUTO-08x08", resource.getImageIcon(new Dimension(8, 8))); |
174 | | testImage(16, 16, "housenumber_small-AUTO-16x16", resource.getImageIcon(new Dimension(16, 16))); |
175 | | testImage(24, 24, "housenumber_small-AUTO-24x24", resource.getImageIcon(new Dimension(24, 24))); |
| 173 | testImage(8, 6, "housenumber_small-AUTO-08x08", resource.getImageIcon(new Dimension(8, 8))); |
| 174 | testImage(16, 12, "housenumber_small-AUTO-16x16", resource.getImageIcon(new Dimension(16, 16))); |
| 175 | testImage(24, 18, "housenumber_small-AUTO-24x24", resource.getImageIcon(new Dimension(24, 24))); |
176 | 176 | testImage(36, 27, "housenumber_small-AUTO-36x27", resource.getImageIcon(new Dimension(36, 27))); |
177 | 177 | } |
178 | 178 | |
… |
… |
public void testImageIcon() throws IOException {
|
184 | 184 | public void testImageIconBounded() throws IOException { |
185 | 185 | ImageResource resource = new ImageProvider("presets/misc/housenumber_small").getResource(); |
186 | 186 | testImage(8, 6, "housenumber_small-BOUNDED-08x08", resource.getImageIconBounded(new Dimension(8, 8))); |
187 | | testImage(16, 12, "housenumber_small-BOUNDED-16x16", resource.getImageIconBounded(new Dimension(16, 16))); |
188 | | testImage(24, 18, "housenumber_small-BOUNDED-24x24", resource.getImageIconBounded(new Dimension(24, 24))); |
| 187 | testImage(12, 9, "housenumber_small-BOUNDED-16x16", resource.getImageIconBounded(new Dimension(16, 16))); |
| 188 | testImage(12, 9, "housenumber_small-BOUNDED-24x24", resource.getImageIconBounded(new Dimension(24, 24))); |
189 | 189 | } |
190 | 190 | |
191 | 191 | /** |
diff --git a/test/unit/org/openstreetmap/josm/tools/ImageResizeModeTest.java b/test/unit/org/openstreetmap/josm/tools/ImageResizeModeTest.java
index 2f014281c..9b606ce16 100644
a
|
b
|
public void testComputeDimensionAuto() {
|
39 | 39 | assertEquals(new Dimension(64, 48), ImageResizeMode.AUTO.computeDimension(new Dimension(64, 48), image)); |
40 | 40 | assertEquals(new Dimension(32, 24), ImageResizeMode.AUTO.computeDimension(new Dimension(32, -1), image)); |
41 | 41 | assertEquals(new Dimension(21, 16), ImageResizeMode.AUTO.computeDimension(new Dimension(-1, 16), image)); |
42 | | assertEquals(new Dimension(24, 32), ImageResizeMode.AUTO.computeDimension(new Dimension(24, 32), image)); |
| 42 | assertEquals(new Dimension(24, 18), ImageResizeMode.AUTO.computeDimension(new Dimension(24, 32), image)); |
43 | 43 | } |
44 | 44 | |
45 | 45 | /** |